Event listeners cannot be applied to elements that are returned from a function

I have been grappling with a puzzle for an extended period of time. In my code, I have an entity called the "To-Do List". Within this list, I am attempting to enable functionality for the buttons labeled "doneButton" and "deleteButton" using the "addEventListener" method.

Unfortunately, the buttons are not functioning as expected. It's peculiar because when I execute console.log(todoItem.doneButton), it correctly displays the button. However, immediately following that line where I attempt to apply the "addEventListener" to the same element, nothing happens at all.

(function() {
    function createAppTitle(title) {
        let appTitle = document.createElement('h2');
        appTitle.textContent = title;
        appTitle.classList.add('mt-5', 'mb-3');
        return appTitle;
    }

    function createToDoList() {
        let list = document.createElement('ul')
        return list;
    }

    function createToDoForm() {
        let buttonWrapper = document.createElement('div')
        let form = document.createElement('form')
        let input = document.createElement('input')
        let button = document.createElement('button')

        form.classList.add('input-group', 'mb-3');
        input.classList.add('form-control');
        input.placeholder = 'Enter the name of the task';
        buttonWrapper.classList.add('input-group-append');
        button.classList.add('btn', 'btn-primary');
        button.textContent = 'Add a task';

        buttonWrapper.append(button);
        form.append(input);
        form.append(buttonWrapper);

        return {
            form,
            input,
            button
        };
    }

    function createToDoItem (name) {
        let item = document.createElement('li')
        let buttonGroup = document.createElement('div')
        let doneButton = document.createElement('button')
        let deleteButton = document.createElement('button')

        item.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
        item.textContent = name;

        buttonGroup.classList.add('btn-group','btn-group-sm');
        doneButton.classList.add('btn','btn-success');
        doneButton.textContent = "Done";
        deleteButton.classList.add('btn','btn-danger');
        deleteButton.textContent = 'Delete';

        buttonGroup.append(doneButton);
        buttonGroup.append(deleteButton);
        item.append(buttonGroup);

        return {
            item,
            doneButton,
            deleteButton
        }
    }

    document.addEventListener('DOMContentLoaded', function () {
            let container = document.querySelector('.container');
            let appTitle = createAppTitle('Name of the Target');
            let list = createToDoList();
            let form = createToDoForm();
            let todoItems = [createToDoItem('Book your trip'), createToDoItem('Fly to Dubai'), createToDoItem('Book' +
                ' your trip')];
            container.append(appTitle);
            container.append(form.form);
            container.append(list);
            list.append(todoItems[0].item)
            list.append(todoItems[1].item)
            list.append(todoItems[2].item)

        form.form.addEventListener('submit', (e)=> {
            e.preventDefault();
            if (!form.input.value) {
                return;
            }

            let todoItem = createToDoItem(form.input.value);
            console.log(todoItem.doneButton)
            todoItem.doneButton.addEventListener('click', function () {
                console.log('done button clicked');
            });
            todoItem.deleteButton.addEventListener('click', ()=> {
                console.log('delete button clicked');
            })

            list.append(createToDoItem(form.input.value).item)
            form.input.value = '';
            });
        })
})();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8>
    <title>ToDo</title>
    <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f4969b9b808780869584b4c0dac1dac7">[email protected]</a>/dist/css/bootstrap.min.css"
        integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
        crossorigin="anonymous">
    <script src="index.js" defer></script>
</head>
<body>
<div id="toDo" class="container"></div>
</body>
</html>

Answer №1

You need to include the event inside the createToDoItem()

(function() {
    function createAppTitle(title) {
        let appTitle = document.createElement('h2');
        appTitle.textContent = title;
        appTitle.classList.add('mt-5', 'mb-3');
        return appTitle;
    }

    function createToDoList() {
        let list = document.createElement('ul')
        return list;
    }

    function createToDoForm() {
        let buttonWrapper = document.createElement('div')
        let form = document.createElement('form')
        let input = document.createElement('input')
        let button = document.createElement('button')

        form.classList.add('input-group', 'mb-3');
        input.classList.add('form-control');
        input.placeholder = 'Enter the name of the task';
        buttonWrapper.classList.add('input-group-append');
        button.classList.add('btn', 'btn-primary');
        button.textContent = 'Add a task';

        buttonWrapper.append(button);
        form.append(input);
        form.append(buttonWrapper);

        return {
            form,
            input,
            button
        };
    }

    function createToDoItem (name) {
        let item = document.createElement('li')
        let buttonGroup = document.createElement('div')
        let doneButton = document.createElement('button')
        let deleteButton = document.createElement('button')

        item.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'align-items-center');
        item.textContent = name;

        buttonGroup.classList.add('btn-group','btn-group-sm');
        doneButton.classList.add('btn','btn-success');
        doneButton.textContent = "Done";
        deleteButton.classList.add('btn','btn-danger');
        deleteButton.textContent = 'Delete';

        buttonGroup.append(doneButton);
        buttonGroup.append(deleteButton);
        item.append(buttonGroup);

        doneButton.addEventListener('click', function () {
            console.log('done button clicked');
        });
        deleteButton.addEventListener('click', ()=> {
            console.log('delete button clicked');
        })

        

        return {
            item,
            doneButton,
            deleteButton
        }
    }

    document.addEventListener('DOMContentLoaded', function () {
            let container = document.querySelector('.container');
            let appTitle = createAppTitle('Name of the Target');
            let list = createToDoList();
            let form = createToDoForm();
            let todoItems = [createToDoItem('Book your trip'), createToDoItem('Fly to Dubai'), createToDoItem('Book' +
                'your trip')];
            container.append(appTitle);
            container.append(form.form);
            container.append(list);
            list.append(todoItems[0].item)
            list.append(todoItems[1].item)
            list.append(todoItems[2].item)

        form.form.addEventListener('submit', (e)=> {
            e.preventDefault();
            if (!form.input.value) {
                return;
            }

            let todoItem = createToDoItem(form.input.value);
            console.log(todoItem.doneButton)
            list.append(createToDoItem(form.input.value).item)
              form.input.value = '';
            });
        })
})();
<!DOCTYPE html>
<html lang="en>
<head>
    <meta charset="UTF-8>
    <title>ToDo>
    <link
        rel="stylesheet"
        href="https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="45272a2a31363137243505716b706b76">[email protected]</a>/dist/css/bootstrap.min.css"
        integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2"
        crossorigin="anonymous">
    <script src="index.js" defer></script>
</head>
<body>
<div id="toDo" class="container></div>
</body>
</html>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Developing an Addon for Firefox using XUL and JavaScript

I am interested in creating a Firefox Addon that dynamically generates a button in the webpage's DOM when a specific page like www.google.com is loaded. This button, when clicked, will redirect to another page such as www.stackoverflow.com. It is imp ...

Minifying Angular using grunt leads to 'Error initializing module' issue

Currently, I have multiple controllers, models, and services set up as individual files for preparation before minification. My goal is to combine and minify all these files into one JS file for production. To illustrate how my files are structured, here ...

Issue with splitting a JavaScript function in JQuery within the Wordpress platform can cause errors

My split function seems to be causing an error, as shown in this console error image. There is a hidden input field within the PHP file: <input class="file-id" name="_file-id" type="hidden" value="<?php echo esc_attr($file_ids); ?>" /> I hav ...

Dynamic content for tooltips in Angular

Currently, I am facing a challenge where I need to dynamically populate content in a tooltip by executing a function with a parameter. This parameter holds the crucial information required to update the tooltip content. The complexity arises from the fact ...

Determining the type of a form element by identifying the select using its name attribute

<FORM NAME="form1" METHOD="POST" ACTION="survey.php"> <p>q2: Who is your closest friend?</P> <select name='q2' id='q21'> <option value='0'>Select a Name</option> < ...

Combine various arrays of objects into one consolidated object

Problem: There are untyped objects returned with over 100 different possible keys. I aim to restructure all error objects, regardless of type, into a singular object. const data = [ { "type":"cat", "errors" ...

Is the number 9933272057275866 truly magical?

I encountered a strange issue that I cannot quite understand. It has left me quite baffled. When I attempt to increase the number 9933272057275866 by 1, it somehow adds 2 instead!!! Here is the code snippet: let test = 9933272057275866; let test2 = test+1 ...

The returned state from setState(prev) seems to be in the opposite order when referencing another useState variable within a useEffect

As part of my interactive chat simulation project, I have implemented a feature where users can click on a button named obj4 to start their chat session. Initially, everything functions smoothly, displaying messages 1-4 in the correct order. However, when ...

Adding a class to a different UL tab from the tab div in jQuery tabs - a guide

Looking to implement a tabs navigation using jQuery without the jQuery Tabs UI. Essentially, when a user clicks on a list item, the script selects the list element with data-tab="X" and adds the class current, making the link visible (default op ...

Tips for restricting users from inputting spaces into a form field using ReactJS

Within my application, I have developed a specialized component named QueryForm that serves the purpose of enabling search capabilities. The code snippet being outputted by this component is as follows: ...

Changing focus to 'DIV' element without JQuery using Javascript and Angular's ng-click event

Instructions for using an Angular directive to set focus on a "DIV" element when clicked <a href="#" class="skipToContent" ng-click="showContent()" title="skip-to-main-content">Skip To Main Content</a> <div class="getFocus" role="button" ...

When the React ref current is accessed from outside the component where it is initialized, it returns

Encountering an issue with React ref. Today, I was pondering on how to access DOM elements from sub-components within a main component. Fortunately, I stumbled upon a solution using React refs on a website. I set up a ref in my main component and linked i ...

Error in JavaScript: Uncaught TypeError - Unable to access the "left" property of an undefined object

This error is really frustrating and I've come across several inquiries regarding this console issue. It's not providing enough information in the chrome console for me to effectively troubleshoot. /** * Adjustment of dropdown menu positio ...

grabbing data from different domains using jQuery

I attempted to implement cross-domain AJAX examples, but unfortunately, it did not function as expected. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr" lang="fr"> <head> <meta http-equiv="Content-Type" content="text/ht ...

Creating concise one-liner If statements with Handlebars: a simple guide

I am seeking clarification on the correct syntax for this code snippet: <li class="nav-item {{# if undefined !== user}} hidden {{/if}}"> My goal is to add the class name hidden only if the user variable exists. When I try implementing this, it res ...

Guide on transforming an array of objects into a fresh array

I currently have this array: const initialData = [ { day: 1, values: [ { name: 'Roger', score: 90, }, { name: 'Kevin', score: 88, }, { name: 'Steve&apo ...

Ways to access a function variable within an AJAX `done` function

This is the JavaScript function I am working with: $('.editable').change(function () { event.preventDefault(); var el_text = this.lastElementChild; var action = this.action; var method = this.method; var data = $(this).serialize(); ...

Using JavaScript and jQuery to fill a div with content from an external file

Feeling extremely frustrated at the moment. I am struggling to make this work and can't figure out why it's not working. My current challenge involves populating a div with content from another HTML file. Below is the code snippet: <script s ...

Fetching database entries upon page load instead of using the keyup function in JavaScript

Here is an HTML form input provided: <input type="text" id="username" value=""> In this scenario, when a username like "John" is entered and the enter button is pressed, the script below retrieves database records: $(function(){ //var socket = ...

Fetching real-time Twitter search feeds through dynamic AJAX requests

Previously, I successfully used JSON to retrieve hash tag feeds from Twitter and Facebook. However, currently the feeds are not updating dynamically, indicating a need for Ajax implementation. Unfortunately, my lack of knowledge in Ajax is hindering this ...