JavaScript DOM Scripting By Example Improving the Application Code Next Steps

Miguel Rivera
Miguel Rivera
21,679 Points

I changed the textContent from "Confirm" to "Confirmed" when the is checked but the checkbox disappeared.Why?

When the checkbox is checked the textContent change to "Confirmed" but the checkbox disappear. Why does it happens?

We can not help you without looking at your code. It's as simple as that. Once you posted your code in the forum we will be happy to help.

Jordan Hoover
Jordan Hoover
Python Web Development Techdegree Graduate 55,951 Points

Hey guys,

Believe it has to do with him replacing the entire contents of the label.

Here's the code he's looking at (before his changes):

ul.addEventListener('change', (e) => {
  const checkbox = event.target;
  const checked = checkbox.checked;
  const listItem = checkbox.parentNode.parentNode;

  if (checked) {
    listItem.className = 'responded';
//the task is to change the label to say 'Confirm' when checked. This can be accessed through listItem
  } else {
    listItem.className = '';
//the task is to change the label to say 'Confirmed?' when checked. This can be accessed through listItem
  }
});

My snapshot here: https://w.trhou.se/euc8gxg663

Hope this helps others who are looking for answers.

2 Answers

Robert Cooper
Robert Cooper
20,257 Points

As Alex-Christian Lazau mentioned, you need to target the text node within the label element. You can do this by using the .childNodes[0] property on the label element. The index of 0 refers to the label's text node in this case.

Here is the code I used for this problem:

  ul.addEventListener('change', (e) => {
    const checkbox = event.target;
    const checked = checkbox.checked;
    const label = checkbox.parentNode;
    const listItem = checkbox.parentNode.parentNode;
    if (checked) {
      listItem.className = "responded";
      label.childNodes[0].textContent = 'Confirmed';
    } else {
      listItem.className = "";
      label.childNodes[0].textContent = 'Confirm';
    }
  });

You can read more about the .childNodes property on MDN.

I ran into the same problem with the checkbox disappearing when I did this:

      ul.addEventListener('change', (e) => {
    const checkbox = event.target;
    const checked = checkbox.checked;
    const listItem = checkbox.parentNode.parentNode;

    if (checked) {
      listItem.className = 'responded';
      listItem.children[1].textContent = 'Confirmed';
    } else {
      listItem.className = '';
      listItem.children[1].textContent = 'Confirm'
    }
  });

Here is my solution:

    ...
    appendToLi('label', 'textContent', 'Confirm')
      .appendChild(createElement('input', 'type', 'checkbox'));
    ...

  ul.addEventListener('change', (e) => {
    const checkbox = event.target;
    const checked = checkbox.checked;
    const listItem = checkbox.parentNode.parentNode;

    if (checked) {
      listItem.className = 'responded';
      listItem.children[1].innerHTML = 'Confirmed<input type="checkbox" checked="checked">';
    } else {
      listItem.className = '';
      listItem.children[1].innerHTML = 'Confirm<input type="checkbox">'
    }
  });

I added the innerHTML instead of the textContent because the textContent was apparently removing the checkbox.

Also if I tried to use

listItem.children[1].textContent = 'Confirmed<input type="checkbox" checked="checked">';

it simply looked like:

Confirmed<input type="checkbox" checked="checked">

on the page.

Using innerHTML resolved that and fixed the issue for me.

Alex-Christian Lazau
Alex-Christian Lazau
10,930 Points

textContent replaces the whole content of an element with "text/plain", so every child element is removed.

Typing

listItem.children[1].textContent = 'Confirmed<input type="checkbox" checked="checked">';

renders the string as "text/plain", the HTML isn't encoded, whereas innerHTML replaces the whole content of an element with "text/html". But be aware that this can lead to security issues and I don't recommend using innerHTML. Also if the label would contain more elements, you would have to rewrite everything, which is inefficient.

Try instead using something like this:

// Find specific text node that contains a substring
// and replace its content with text
function changeTextNode(node, substring, text) {
  for(let i = 0; i < node.childNodes.length; i++) {
    let currentNode = node.childNodes[i];
    if (currentNode.nodeType == Node.TEXT_NODE &&
        currentNode.textContent.indexOf(substring) != -1) {
      return currentNode.textContent = text;
    }
  }
};

This looks over every child node of an element and tests if it's a text node and contains the given substring. Then it replaces the textContent with text. You can use it like this:

changeTextNode(listItem.querySelector('label'), 'Confirm', 'Confirmed');

I hope this helps!

I wish I could upvote your reply! Good information!

Robert Cooper
Robert Cooper
20,257 Points

Alex-Christian Lazau you nailed it. Thanks for posting that solution as it helped me with the same issue.