Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

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
220,378 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.