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 Adding and Removing Names RSVP Checkbox

Declaring "li" variable outside of the event handler causes new additions to replace the last. Why?

Hello,

In the video, the "li" variable is declared with const inside the form event handler. The results are expected. Each submission grows the list of names on the page. But, declaring the "li" variable with const at the top of the javascript file has different results. Each new submission simply replaces the previous one. Why is that? What about the scope of this particular variable would cause this behavior?

Expected results:

const form = document.getElementById("registrar");
const input = form.querySelector("input");
const checkbox = document.createElement("input");
const ul = document.getElementById("invitedList");
const label = document.createElement("label");

form.addEventListener("submit", (e) => {
    e.preventDefault();
    const li = document.createElement("li"); // <<<<<<<<<<<<<<
    let inputText = input.value;
    input.value = "";
    li.textContent = inputText;
    label.textContent = "Confirmed";
    checkbox.type = "checkbox";
    label.appendChild(checkbox);
    li.appendChild(label);
    ul.appendChild(li);
})

ul.addEventListener("change", (e) => {
    let checked = e.target.checked;
    const listItem = checkbox.parentNode.parentNode;
    if (checked) {
        listItem.className = "responded";
        console.log(checked);
    } else {
        listItem.className = "";
    }
})

Unexpected results:

const form = document.getElementById("registrar");
const input = form.querySelector("input");
const checkbox = document.createElement("input");
const ul = document.getElementById("invitedList");
const label = document.createElement("label");
const li = document.createElement("li"); // <<<<<<<<<<<<<< 

form.addEventListener("submit", (e) => {
    e.preventDefault();

    let inputText = input.value;
    input.value = "";
    li.textContent = inputText;
    label.textContent = "Confirmed";
    checkbox.type = "checkbox";
    label.appendChild(checkbox);
    li.appendChild(label);
    ul.appendChild(li);
})

ul.addEventListener("change", (e) => {
    let checked = e.target.checked;
    const listItem = checkbox.parentNode.parentNode;
    if (checked) {
        listItem.className = "responded";
        console.log(checked);
    } else {
        listItem.className = "";
    }
})

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<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 src="app.js"></script>
</body>
</html>

style.css

/* ================================= 
  Element Styles
==================================== */

* {
  box-sizing: border-box;
}
body {
  font-family: 'Lato', sans-serif;
  color: #4c4c4c;
  background: #f8fdf3;
}
h1,
p,
form button {
  color: white;  
}
h1 {
  font-family: 'Courgette', cursive;
  text-shadow: 0 1px 0 rgba(0,0,0, .4);
  line-height: .65;
  margin-top: .5em;
  margin-bottom: 0;
}
h2 {
  margin-top: 0;
}
p {
  font-size: 1.1em;
  text-shadow: 0 1px 0 rgba(0,0,0, .25);
}
form {
  width: 60%;
  background: white;
  display: inline-block;
  overflow: hidden;
  display: -webkit-flex;
  display: flex;
  border-radius: .2em;
  border: solid 4px white;
  box-shadow: 0 1px 14px rgba(0,0,0, .12);
}
form button {
  padding: 0 1em;
  font-size: 1em;
  background: #7bcbc4;
  border-radius: .2em;
}
ul {
  list-style: none;
  padding: 0;
  margin: 2em 0 1em;
}
ul li {
  padding: 1em;
  background: #fff;
  border-radius: .2em;
  border: solid 1px rgba(88, 183, 205, .2);
  border-bottom: solid 2px rgba(88, 183, 205, .2);
  position: relative;
}
button {
  cursor: pointer;
}
input, 
button {
  border: none;
  outline: none;
}
header {
  text-align: center;
  background: linear-gradient(90deg, #d4eece, #55b3d0, #1e7eb7),
              url('../images/header-bg.jpg') no-repeat;
              background-blend-mode: multiply;    
              background-size: cover;   
}
header input {
  padding: 12px;
  font-size: 1.15em;
  width: 100%;
}
li span, 
li input[type=text] {
  color: #707070;
  font-size: 1.3em;
  margin-bottom: .3em;
}
li input[type=text] {
  padding: .2em;
  width: 95%;
  border: 1px dotted rgba(0,0,0, .2);
}
li label {
  font-size: .9em;
  display: block;
  color: rgba(112, 112, 112, .55);
}
li span, 
li input[type=text]:first-child {
  display: block;
}
li button {
  font-size: .78em;
  margin-top: 1.65em;
  margin-right: .4em;
  border-radius: .3em;
  padding: .4em .6em;
  color: white;
  background: #58b7cd;
}
li button:last-child {
  background: rgba(88, 183, 205, .5);
}
.wrapper {
  width: 100%;
  max-width: 900px;
  margin: 2.5em auto;
  border-radius: .35em;
  background: #fcfcfc;
  overflow: hidden;
  box-shadow: 0 0 26px rgba(0,0,0, .13);
}
div > input:last-child {
  font-size: 1em;
  margin-left: 6px;
}
div > label {
  color: #767676;
}

/* responded */
.responded {
  transition: 0.4s;
  border-color: rgba(88, 183, 205, .9);
}
.responded label {
  transition: 0.4s;
  color: rgba(88, 183, 205, 1);
}

/* ================================= 
  Media Queries
==================================== */

@media (min-width: 0) and (max-width: 768px) {
  header {
    padding: 1.25em;
  }
  h1 {
    font-size: 3.6em;
    margin: .3em 0 0;
  }
  ul li {
    margin-bottom: 1em;
  }
  form {
    width: 95%;
    -webkit-flex-direction: column;
    flex-direction: column;
    margin: auto;
    margin-top: 2.5em;
  }
  form button {
    padding: 12px 0;
    margin-top: .5em;
  }
  form input {
    font-size: 1em;
    text-align: center;
  }
  .wrapper {
    margin: 0;
  }
  .main {
    padding: 2em 1em .75em;
  }
}

@media (min-width: 769px) {
  header {
    height: 280px;
    padding: 2.5em 1em 1em;  
    background-position: 0 -95px; 
  }
  .main > div {
    float: right;
    display: inline-block;
    margin-top: 12px;
    margin-right: 1.25%;
  }
  div > label {
    margin-top: 12px;
  }
  h1 {
    font-size: 5.8em;
  }
  h2 {
    float: left;
    font-size: 1.9em;
    margin-left: 1.25%;
  }
  form {
    margin: 4.15em auto 0;
    z-index: 3000;
    position: relative;
  }
  .wrapper {
    width: 90%;
  }
  .main {
    padding: 3.8em 1.5em .75em;
    position: relative;
    z-index: 10;
  }
  ul {
    display: -webkit-flex;
    display: flex;
    clear: both;

    -webkit-justify-content: space-between;
    justify-content: space-between;
    -webkit-flex-wrap: wrap;    
    flex-wrap: wrap;
    padding-top: 1.25em;
  }
  ul li {
    -webkit-flex-grow: 1;
    flex-grow: 1;
    -webkit-flex-basis: 47.5%;
    flex-basis: 47.5%;
    margin: 0 1.25% 1em;
  }
}
@media (min-width: 880px) { 
  ul li {
    -webkit-flex-basis: 20%;
    flex-basis: 20%;
  }
}

1 Answer

Steven Parker
Steven Parker
229,732 Points

This is not really a scope issue. If you move the line with "createElement" outside of the function, you'll have only one element for the entire program. But if you call "document.createElement("li");" inside the function, you'll get a new element each time the function runs, which is what you want.

You'll have the same issue with "label", too.