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

Why the if statement doesn't work with JS function?

Hi,

I've tried several times in various configuration but the following statement doesn't work:

if (document.querySelector('li')) {alert('it works');}

Basically it's a to-do list and I want the button to appear just after UL (<ul class="list-group">) when a user adds input and code will dynamically create a LI element inside UL. Just to check the code instead of a button reference in the if statement I've put alert().

The statement doesn't work, but when I manually add LI element into the html document it works fine as it should. For dynamic Li creation I'm using a function that also creates bootstrap classes for LI creation and several event listeners. Maybe it's the JS code that creates LI elements but it should change the DOM (I checked in Chrome Dev. Tools that the LI elements are correctly added to she HTML - but still no idea why the IF doesn't work).

CREATE LI ELEMENT WITH BOOTSTRAP CLASSES FUNCTION

function CreateLi() {

    let li = document.createElement('li');
    li.className = 'list-group-item list-group-item-action';
    let paragraph = document.createElement('p');
    paragraph.className = 'd-inline';
    let label = document.createElement('label');
    label.className = 'checkbox-inline';
    let InputDiv = document.createElement('div');
    InputDiv.className = 'input-group';
    let TextDiv = document.createElement('div');
    TextDiv.className = 'input-group-text mr-2';
    let InputElement = document.createElement('input');
    let ButtonDiv = document.createElement('div');
    ButtonDiv.className = 'btn-group mr-2 float-right';
    let RemoveButton = document.createElement('button');
    RemoveButton.className = 'btn btn-outline-danger btn-sm remove';
    let DownButton =document.createElement('button');
    DownButton.className = 'btn btn-outline-primary btn-sm GoDown';
    let UpButton =document.createElement('button');
    UpButton.className= 'btn btn-outline-primary btn-sm GoUp';
    let ButtonDiv1 = document.createElement('div');
    ButtonDiv1.className = 'btn-group mr-2 float-right';
    let RemoveDiv = document.createElement('div');
    RemoveDiv.className = 'btn-group mr-2 float-right';
    paragraph.textContent = Item.value;
    ul.appendChild(li);
    li.appendChild(label);
    label.appendChild(InputDiv);
    InputDiv.appendChild(TextDiv);
    TextDiv.appendChild(InputElement);
    InputElement.setAttribute("type", "checkbox"); 
    InputElement.setAttribute("aria-label", "Checkbox for following text input");
    li.appendChild(paragraph);
    li.appendChild(RemoveDiv);
    li.appendChild(ButtonDiv);
    li.appendChild(ButtonDiv1);
    DownButton.textContent = "Down";
    UpButton.textContent = 'Up';
    RemoveButton.textContent = "Remove";
    ButtonDiv1.appendChild(UpButton);
    UpButton.setAttribute("type", "button");
    ButtonDiv.appendChild(DownButton);
    DownButton.setAttribute("type", "button");
    RemoveDiv.appendChild(RemoveButton);
    RemoveButton.setAttribute("type", "button");
} 

EVENT LISTENER WITH LI CREATION FUNCTION

Item.addEventListener ('keyup', (e) => {

    const EnterInput= e.key;

if (EnterInput == 'Enter') {

if (Item.value ) {


    CreateLi();

    Item.value = '+ Add an item...';    



    }

HTML

<!DOCTYPE html>
<html lang="pl">
<head>

<!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">



    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">


    <!-- Google Fonts -->

   <link href="https://fonts.googleapis.com/css?family=Roboto|Signika" rel="stylesheet">
   <link href="https://fonts.googleapis.com/css?family=Chivo|Comfortaa" rel="stylesheet">
   <link href="https://fonts.googleapis.com/css?family=Gudea|Open+Sans" rel="stylesheet">
   <link rel="stylesheet"  type="text/css" href="styles.css">


<title>Page Title</title>
</head>
<body>
<div class="container-fluid h_back">
    <div class="row">
            <div class="col-lg-12 ">
                <h1 class="text-center  ">Easy ToDO</h1>
            </div>
            <div class="col-lg-2 mt-2 ">

            </div>
    </div>
</div>






<div class="container">
    <div class="row">
        <div class="col-lg-4 offset-lg-4">
            <div class="input-group input-group-sm mb-3 mt-3">
                <input type="text" class="form-control addItemInput" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-sm" value= '+ Add an item...' id='AddItem'> 
            </div>
        </div>
        <div class="col-lg-1 offset-lg-2 mt-3">

                <p class="small text-center PrintMe"><img src="Icons/001-printer.png" class="mx-auto d-block" >Print list</p>
        </div>
        <div class="col-lg-1  mt-3">
            <p class="small text-center PrintMe"><img src="Icons/009-email-1.png" class="mx-auto d-block" ><a href="mailto:name@email.com">Send list</a></p>
        </div>
    </div>
    <div class="row">
        <div class="col-lg">
            <ul class="list-group">

            </ul> 
        </div> 



    </div> 

        <div class="row">
            <div class="col-lg-12 text-center mt-3 createButton">
                <button type="button" class="btn btn-danger col-lg-2 d-none" id="ClearList">Clear list</button>
            </div>
        </div>

</div>



<script src='script.js'></script>
</body>
</html>
Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 Points

The reason it doesn’t work is because no <li> element exist on the page at the time that the code is running. The code inside the if block only runs if the expression evaluates to something true or truthy, and because there are no li elements, it's null which is falsy.

I haven’t dug into there rest of the code to understand it well enough. I also don’t complete follow what the goal is. Is it possible for you to post this as a workspace snapshot/codepen/or put on GitHub?

5 Answers

Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 Points

When the script loads all the code will run from top to bottom until the end. So that line of code, if (document.querySelector('li')) {alert('it works’);}, will be run at the beginning when the page loads, and there are no <li> elements in the document at the time. And as of right now, that line of code never gets run again.

Some parts of your code define functions and add event listeners, and those parts of code will get run later on when those events are triggered. So if you want that line of code to get run later on when more <li> elements have been added to the page, you could put it inside one of the functions that will be run later.

function CreateLi() {
    let li = document.createElement('li');
    // skipping over the lines where you build up the contents of the <li> element ...
    ul.appendChild(li);
    // a new <li> element has now been appended to the DOM and will be there when the next line of code is run
    if (document.querySelector('li')) {alert('it works');}
}

I spent many hours on this and now it looks and sounds obvious, I've also tried and now it works. Thank you Brendan for all your effort, detailed answer and sharing very useful improvements.

Hi Brendan,

by default <li> element doesn't exist until. But there is an active event listener and a function which creates <li> elements [CreateLi()], when a user puts some input into the field script creates new <li> element with the input, so <li> elements are created and then expression should be true because <li> elements are added and alert {alert('it works');} should run in my opinion. I'm sharing full code here: https://codepen.io/pellwart/pen/XoEMgg

Brendan Whiting
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Brendan Whiting
Front End Web Development Techdegree Graduate 84,738 Points

I was able to add to-do items to the list, move them up and down, and remove them. What behavior do you want that you don't have right now? Or is it that you have it working but not coded the way you want? This line that you mentioned earlier, I don't see it in the code right now, where would you put it if you wanted to put it back?

if (document.querySelector('li')) {alert('it works');}

Also, this is unrelated, but I see you building up DOM elements step by step in a very painstaking way. You could do it more efficiently and legibly using a template literal:

function CreateLi() {
  let li = document.createElement('li');
  li.className = 'list-group-item list-group-item-action';
  li.innerHTML = `
    <label class="checkbox-inline">
        <div class="input-group">
          <div class="input-group-text mr-2">
            <input type="checkbox" aria-label="Checkbox for following text input">
          </div>
        </div>
      </label>
      <p class="d-inline">${Item.value}</p>
      <div class="btn-group mr-2 float-right">
        <button class="btn btn-outline-danger btn-sm remove" type="button">Remove</button>
      </div>
      <div class="btn-group mr-2 float-right">
        <button class="btn btn-outline-primary btn-sm GoDown" type="button">Down</button>
      </div>
      <div class="btn-group mr-2 float-right">
        <button class="btn btn-outline-primary btn-sm GoUp" type="button">Up</button>
      </div>
  `;
  ul.appendChild(li);
} 

You can add and remove items from the list and it works as it should, but the idea is to add a button when first <li>(item) adds to the page, just for the training instead of a button I want to run alert('it works'); and it still doesn't work - as you said, you can add to-do items to the list and once you add fist item alert box with 'it works' should appear and it doesn't and I don't know why.

This line is visible on the codepen link that I've shared

if (document.querySelector('li')) {alert('it works');}

Thank you for sharing the template, I'm still learning and agree that your way is much easier.

It doesn't work even if I add first <li> (to-do item), the same result if I try to add second or third <li>. I was trying to add <li> on the page (just inserted <li> into <ul> and reloaded the page) without JS code - CreateLi and then the code worked as it should, but when I try to add to-do items still nothing.

It's 244 line of the code on Codepen, penultimate script in JS file: https://codepen.io/pellwart/pen/XoEMgg

Image link: https://imgur.com/a/ZdwgFeN