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

Justin Hicks
Justin Hicks
14,290 Points

DOM scripting by example. In improving the code I'm just looking for a little feedback.

Please keep in mind this is before any refactoring and I cut out the other features to keep the focus on the checkbox change. Is this a good way to handle the checkbox feature to start off with or will this cause lots of problems?

const form = document.getElementById('registrar');
const input = registrar.querySelector('input');
const ul = document.getElementById('invitedList');

form.addEventListener('submit', (event) => {
  event.preventDefault();
  const text = input.value;
  input.value = '';
  const li = document.createElement('li');
  li.textContent = text;
  const label = document.createElement('label');
  label.textContent = 'Confirmed';
  const checkbox = document.createElement('input');
  checkbox.type = 'checkbox';
  li.appendChild(label);
  label.appendChild(checkbox);
  const edit = document.createElement('button');
  edit.textContent = 'Edit';
  li.appendChild(edit);
  const remove = document.createElement('button');
  remove.textContent = 'Remove';
  li.appendChild(remove);
  ul.appendChild(li);
});

ul.addEventListener('change', (event) => {
  const checkbox = event.target;
  const checked = checkbox.checked;
  const label = checkbox.parentNode;
  const li = checkbox.parentNode.parentNode;
  if(checked) {
    li.className = 'responded';
    label.textContent = 'Unconfirm';
    label.appendChild(checkbox);
  } else {
    li.className = '';
    label.textContent = 'Confirmed';
    label.appendChild(checkbox);
  }
});

2 Answers

Christopher Debove
PLUS
Christopher Debove
Courses Plus Student 18,373 Points

Hello

Seeing your change handler, I see 2 optimisations:

The larger one :

To change the text of the label you're creating a new textnode + re-appending the checkbox. Try to see if you can directly edit the textContent of the TextNode (label.firstChild)

The Second one:

You're changing directly the className via affectation. If you had another class on the element, it would be bad and you would need to keep check of it.

Depending on your level of browser compatibility you could use the ClassList API : Element.classList (ex: li.classList) and see the toggle method of this object.

Justin Hicks
Justin Hicks
14,290 Points

The reason for re-appending the check box is because the textnode is re-created so the new textnode needs the checkbox added back to it. As far as changing the class name like that is how it's shown to do in the video. I did think about toggle but are they not the same? When you toggle the class name on then toggle it off does it not just change the class name from responded to an empty string?

Christopher Debove
Christopher Debove
Courses Plus Student 18,373 Points

Oh yeah if you want to use just what's in the course, there's not many to do here.

  • ClassList.toggle can take 2 parameters, toggle(className: string, activate: boolean) On the second parameter if you pass true it add the class, if you pass false it removes it

  • For the checkbox, the optimisation I was proposing, is to directly manage the content of the textnode so you don't have to rebuild the entire label =)

Justin Hicks
Justin Hicks
14,290 Points

oh okay thanks for the help, now I know I need to look into some textnode content management because I have no idea how to do that lol

Christopher Debove
Christopher Debove
Courses Plus Student 18,373 Points

For the textContent exactly like with an Element, in your case :

const label = checkbox.parentNode;
const textNode = label.firstChild;
textNode.textContent = "Confirmed" // Or "Unconfirmed" depending the case
// or
const label = checkbox.parentNode;
label.firstChild.textContent = "Confirmed" // Or "Unconfirmed" depending the case

// In place of
const label = checkbox.parentNode;
label.textContent = "Confirmed" // Or "Unconfirmed" depending the case
label.appendChild(checkbox);
Justin Hicks
Justin Hicks
14,290 Points

Huge thanks, Chris!! That solved my issue which I spent hours trying to figure out.

Justin Hicks
Justin Hicks
14,290 Points

When I added the button handler back I ran into something that has me baffled. Everything with the buttons works correctly except when I click the edit button then change what is in the text input when I click save all buttons disappear as well as the checkbox? I need help understanding why

const form = document.getElementById('registrar');
const input = registrar.querySelector('input');
const ul = document.getElementById('invitedList');

form.addEventListener('submit', (event) => {
  event.preventDefault();
  const text = input.value;
  input.value = '';
  const li = document.createElement('li');
  const span = document.createElement('span');
  span.textContent = text;
  li.appendChild(span);
  const label = document.createElement('label');
  label.textContent = 'Confirmed';
  const checkbox = document.createElement('input');
  checkbox.type = 'checkbox';
  li.appendChild(label);
  label.appendChild(checkbox);
  const edit = document.createElement('button');
  edit.textContent = 'Edit';
  li.appendChild(edit);
  const remove = document.createElement('button');
  remove.textContent = 'Remove';
  li.appendChild(remove);
  ul.appendChild(li);
});

ul.addEventListener('change', (event) => {
  const checkbox = event.target;
  const label = checkbox.parentNode;
  const checked = checkbox.checked;
  const li = checkbox.parentNode.parentNode;
  if(checked) {
    li.className = 'responded'
    label.textContent = 'Unconfirm';
    label.appendChild(checkbox);
  } else {
    li.className = '';
    label.textContent = 'Confirmed';
    label.appendChild(checkbox);
  }
});

ul.addEventListener('click', (event) => {
  if(event.target.tagName === 'BUTTON') {
    const button = event.target;
    const li = button.parentNode;
    if(button.textContent === 'Remove') {
      ul.removeChild(li);
    } else if(button.textContent === 'Edit') {
      const span = li.firstElementChild;
      const textField = document.createElement('input');
      textField.type = 'text';
      textField.value = span.textContent;
      li.insertBefore(textField, span);
      li.removeChild(span);
      button.textContent = 'Save';
    } else if (button.textContent === 'Save') {
      const textField = li.firstElementChild;
      const span = document.createElement('span')
      span.textContent = textField.value;
      li.insertBefore(span, textField);
      li.removeChild(textField);
      button.textContent = 'Edit';
    } 
  } 
});