JavaScript DOM Scripting By Example Editing and Filtering Names Moving to an Editing State

Nico Trivelli
Nico Trivelli
20,359 Points

insertBefore() + removeChild != replaceChild() ?

Hi everyone,

Just a question, but a clarification first: I don't do this question with any smart aleck intentions, nor implying like I know it all (which is totally untrue!). Just thinking that there might probably be smth else out there I didn't see just by watching the video and checking the docs (MDN).

Having said that, is there any reason why it's better (in this case) to use:

li.insertBefore(input, span);
li.removeChild(span);

... rather than:

li.replaceChild(input, span);

Honestly, to me, they seem really similar, although the second one does both things in one statement, but there probably may be smth I am missing there.

If you want to see the code of this video, this is it:

index.html
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>RSVP App</title>
  <link href="https://fonts.googleapis.com/css?family=Courgette" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css?family=Lato:400,700" rel="stylesheet">
  <link href="css/style.css" rel="stylesheet">
</head>
<body>
  <div class="wrapper">
    <header>
      <h1>RSVP</h1>
      <p>A Treehouse App</p>
      <form id="registrar">
        <input type="text" name="name" placeholder="Invite Someone">
        <button type="submit" name="submit" value="submit">Submit</button>
      </form>
    </header>

    <div class="main">  
      <h2>Invitees</h2>
      <ul id="invitedList"></ul>    
    </div>
  </div>
  <script type="text/javascript" src="app.js"></script>
</body>
</html>

And this is the js file (in the first case the 'edit' button, I used Guil's code; in the second one, the 'save' button, we're challenged to do it ourselves, but then I found this replaceChild() interesting method, and I tried it below) :

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

function createLI(text) {
  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';
  label.appendChild(checkbox);
  li.appendChild(label);
  const editButton = document.createElement('button');
  editButton.textContent = 'edit';
  li.appendChild(editButton);
  const removeButton = document.createElement('button');
  removeButton.textContent = 'remove';
  li.appendChild(removeButton);
  return li;
}

form.addEventListener('submit', (e) => {
  e.preventDefault();
  const text = input.value;
  input.value = '';
  const li = createLI(text);
  ul.appendChild(li);
});

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 = '';
  }
});

ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const button = e.target;
    const li = button.parentNode;
    const ul = li.parentNode;
    if (button.textContent === 'remove') {
        ul.removeChild(li);
    } else if (button.textContent === 'edit') {
        const span = li.firstElementChild;
        const input = document.createElement('input');
        input.type = 'text';
        input.value = span.textContent;
        li.insertBefore(input, span);  // These are the lines I mean
        li.removeChild(span);            // These are the lines I mean
        button.textContent = 'save';
    }   else if (button.textContent === 'save') {
        const input = li.firstElementChild;
        const span = document.createElement('span');
        span.textContent = input.value;
        li.replaceChild(span, input);            // And this one, too.
        button.textContent = 'edit';
    }

  }
});

Thanks in advance for your insight, thoughts, suggestions, corrections, etc.! :)

Josef Aidt
Josef Aidt
7,722 Points

According to the benchmarks here using the method provided in the video runs 57% slower in Chrome 60. Reading through MDN and a few other forums I can't find a benefit in using the insertBefore-removeChild method against replaceChild, and in fact others have recommended using replaceChild over the other. To me, seems like a great find.

Perhaps Steven Parker can provide additional insight.

Nico Trivelli
Nico Trivelli
20,359 Points

Thank you, Joseph!

And thank you also for the reference to the test cases' site, now that's a helpful tip of a place I didn't know.

1 Answer

Steven Parker
Steven Parker
200,416 Points

If the new child position is intended to be the same as the old one, I agree that replaceChild seems to be a better choice. Doing the operations separately might be useful if you wanted to place the new child at a different position in the DOM tree than where the old one was located.

If I had to guess why this was done in two steps in the course, it would be because the two methods introduced have other uses as well where the the more specialized one is less versatile.

Nico Trivelli
Nico Trivelli
20,359 Points

Thanks for the answer, Steven!

Good point. For learning purposes, it's probably better to first learn all the basic blocks and then there's time for us to get more specific.

Honestly, I always really enjoy both Guil's and Joel's courses, they are the perfect combination of explaining things clearly to you but then challenging you to do further steps on your own.