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

Linas Mackonis
Linas Mackonis
7,071 Points

span.textContent disappears after swapping <li> elements in places

Hey all,

I'm trying to combine some JS features that we were learning in the following courses:

JavaScript and the DOM

DOM Scripting by Example

I'm trying to create Unordered List with a series of list items. Each list item has a span with a textContent and 4 buttons. Buttons : Previous and Next are navigational. Whenever you click one of those buttons, it moves the whole list item backward(Previous) or forward(Next).

The problem came to be after I implemented Edit button and defined its behaviour with this code:

if(button.className === '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.className = 'save';
            button.textContent = 'Save';
        } else {
            const input = li.firstElementChild;
            const span = document.createElement('span');
            span.textContent = input.value;
            li.insertBefore(span, input);
            li.removeChild(input);
            button.className = 'edit';
            button.textContent = 'Edit';
        }

What I want to understand is Why and How this code makes the li span.textContent disappear after I click either Previous or Next buttons???

Here is a full js code:

const form = document.querySelector('form');
const ul = document.querySelector('ul');
const listItem = document.querySelector('li');
const addItemInput = document.querySelector('input.add-item-input');
const addItemButton = document.querySelector('button.add-item-button');
const removeItemButton = document.querySelector('button.remove-item-button');

function attach_span(li) {
    const span = document.createElement('span');
    span.textContent = addItemInput.value;
    li.appendChild(span);
}

function attach_br(li) {
    const br = document.createElement('br');
    li.appendChild(br);
}

function attachButton_previous(li) {
    const prev = document.createElement('button');
    prev.className = 'previous';
    prev.textContent = 'Previous';
    if(li.previousElementSibling) li.appendChild(prev);
}

function attachButton_remove(li) {
    const remove = document.createElement('button');
    remove.className = 'remove';
    remove.textContent = 'Remove';
    li.appendChild(remove);
}

function attachButton_edit(li) {
    const edit = document.createElement('button');
    edit.className = 'edit';
    edit.textContent = 'Edit';
    li.appendChild(edit);
}

function attachButton_next(li) {
    const next = document.createElement('button');
    next.className = 'next';
    next.textContent = 'Next';
    li.appendChild(next);
}

function attachListItems(li) {
    attach_span(li);
    attach_br(li);
    attachButton_previous(li);
    attachButton_remove(li);
    attachButton_edit(li);
    attachButton_next(li);
}

addItemButton.addEventListener('click', () => {
    const li = document.createElement('li');
    ul.appendChild(li);
    attachListItems(li);
    addItemInput.value = '';
});

removeItemButton.addEventListener('click', () => {
    const ul = document.getElementsByTagName('ul')[0];
    const li = document.querySelector('li:last-child');
    ul.removeChild(li);
});

ul.addEventListener('click', (e) => {
    if(e.target.tagName === 'BUTTON' ) {
        const button = e.target;
        const li = button.parentNode;
        const ul = li.parentNode;
        const prevEl = li.previousElementSibling;
        const nextEl = li.nextElementSibling;
        if(button.className === 'remove') {
            ul.removeChild(li);
        }
        if(button.className === 'previous') {
            if(prevEl) {
                ul.insertBefore(li, prevEl);
            }
        }
        if(button.className === 'next') {
            if(nextEl) {
                ul.insertBefore(nextEl, li);
            }
        }
        if(button.className === '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.className = 'save';
            button.textContent = 'Save';
        } else {
            const input = li.firstElementChild;
            const span = document.createElement('span');
            span.textContent = input.value;
            li.insertBefore(span, input);
            li.removeChild(input);
            button.className = 'edit';
            button.textContent = 'Edit';
        }
    }
});

And here is HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Testing JavaScript Events</title>
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<body>
    <header></header>
    <article>
        <nav id="main-nav">
            <ul>

            </ul>
        </nav>

        <form class="form">
            <input class="add-item-input" name="itemInput" type="text" title="Input for menu items">
            <button class="add-item-button" type="button">Add item</button>
            <button class="remove-item-button" type="button">Remove last item</button>
        </form>
</article>


    <p id="spitResult"></p>

    <!-- <script src="js/functions.js"></script> -->
    <script src="js/app.js"></script>
</body>
</html>

1 Answer

Linas Mackonis
Linas Mackonis
7,071 Points

I figured out, Hope this will be useful for anyone else. The problem can be fixed if these two conditionals:

if(button.className === '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.className = 'save';
            button.textContent = 'Save';
        } else {
            const input = li.firstElementChild;
            const span = document.createElement('span');
            span.textContent = input.value;
            li.insertBefore(span, input);
            li.removeChild(input);
            button.className = 'edit';
            button.textContent = 'Edit';
        }

are moved above all the other conditionals in the corresponding event listener. Moreover, 'else' statement should be changed into 'else if'.

The final solution should look like this:

ul.addEventListener('click', (e) => {
    if(e.target.tagName === 'BUTTON' ) {
        const button = e.target;
        const li = button.parentNode;
        const ul = li.parentNode;
        const prevEl = li.previousElementSibling;
        const nextEl = li.nextElementSibling;
        if(button.className === '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.className = 'save';
            button.textContent = 'Save';
        } else if(button.className === 'save') {
            const input = li.firstElementChild;
            const span = document.createElement('span');
            span.textContent = input.value;
            li.insertBefore(span, input);
            li.removeChild(input);
            button.className = 'edit';
            button.textContent = 'Edit';
        }

        if(button.className === 'remove') {
            ul.removeChild(li);
        }
        if(button.className === 'previous') {
            if(prevEl) {
                ul.insertBefore(li, prevEl);
            }
        }
        if(button.className === 'next') {
            if(nextEl) {
                ul.insertBefore(nextEl, li);
            }
        }
    }
});