Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript DOM Scripting By Example Improving the Application Code Refactor 2: Readable Branching Logic

Mark Bojesen
Mark Bojesen
12,873 Points

Keep getting: "nameActions[action] is not a function"

HI!

I keep getting a console error like this:

"Uncaught TypeError: nameActions[action] is not a function at HTMLUListElement.ul.addEventListener (app.js:114)"

When Guil does it in the video there seems to be no problem at all, however as the console says, we haven't declared 'action' as a function so why would we invoke it like that? Any suggestions to what I am missing? Thanks!

Code for project:

// DOM waits till page is fully loaded
document.addEventListener('DOMContentLoaded', () => {

    // variables & constants
    const form = document.getElementById('registrar');
    const input = form.querySelector('input');

    const mainDiv = document.querySelector('.main');
    const ul = document.getElementById('invitedList');

    const div = document.createElement('div');
    const filterLabel = document.createElement('label');
    const filterCheckbox = document.createElement('input');

    // checkbox and the effect of hiding invitees who haven't responded.
    filterLabel.textContent = "Hide those who haven't responded";
    filterCheckbox.type = 'checkbox';
    div.appendChild(filterLabel);
    div.appendChild(filterCheckbox);
    mainDiv.insertBefore(div, ul);
    filterCheckbox.addEventListener('change', (e) => {
        const isChecked = e.target.checked;
        const lis = ul.children;
        if (isChecked) {
            for (let i = 0; i < lis.length; i += 1) {
                let li = lis[i];
                if (li.className === 'responded') {
                    li.style.display = ''
                } else {
                    li.style.display = 'none';
                }
            }
        } else {
            for (let i = 0; i < lis.length; i += 1) {
                let li = lis[i];
                li.style.display = '';
            }
        }
    });

    function createLi(text) {
        function createElement(elementName, property, value) {
            const element = document.createElement(elementName);
            element[property] = value;
            return element;
        }

        function appendToLI(elementName, property, value) {
            const element = createElement(elementName, property, value);
            li.appendChild(element);
            return element;
        }

        const li = document.createElement('li');
        appendToLI('span', 'textContent', text);
        appendToLI('label', 'textContent', 'Confirmed')
            .appendChild(createElement('input', 'type', 'checkbox'));
        appendToLI('button', 'textContent', 'Edit');
        appendToLI('button', 'textContent', 'Remove');
        return li;
    }

    // event handler on submit
    form.addEventListener('submit', (e) => {
        e.preventDefault();
        const text = input.value;
        input.value = '';
        const li = createLi(text);
        ul.appendChild(li);
    });

    // event handler reacts to the changed state of the checkbox
    ul.addEventListener('change', (e) => {
        const checkbox = event.target;
        const checked = checkbox.checked;
        const listItem = checkbox.parentNode.parentNode;
        if (checked) {
            listItem.className = 'responded';
        } else {
            listItem.className = '';
        }
    });

    // buttom removes/edits added person
    ul.addEventListener('click', (e) => {
        if (e.target.tagName === 'BUTTON') {
            const button = e.target
            const li = button.parentNode;
            const ul = li.parentNode;
            const action = button.textContent;
            const nameActions = { /* nameActions object */
            remove: () => {
                ul.removeChild(li);
            },
            edit: () => {
                const span = li.firstElementChild;
                const input = document.createElement('input');
                input.type = 'text';
                input.value = span.textContent;
                li.insertBefore(input, span);
                li.removeChild(span);
                button.textContent = 'Save';
            },
            save: () => {
                const input = li.firstElementChild;
                const span = document.createElement('span');
                span.textContent = input.value;
                li.insertBefore(span, input);
                li.removeChild(input);
                button.textContent = 'Edit';
                }
            };
            // select and run action in button's name
            nameActions[action](); /* <-- Line 114 */
        }
    });
});

Any help is much appreciated, thanks!

1 Answer

Steven Parker
Steven Parker
231,271 Points

There's no function named "action".

Instead, action should contain the name of one of the functions ("remove", "edit", or "save").

But when you create the buttons, the names you place on them have capital first letters, so they don't match the names of the functions. You could change either the button texts or the function names, or you could change the case when you assign the variable:

            const action = button.textContent.toLowerCase();