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

Nathan Marshall
Nathan Marshall
6,031 Points

How to call a newly appended div element in Jquery

Hi Guys,

I wonder if you can help. I am currently building a daily tasks application, I have just finished the JQuery Basics Course, and I am putting my new skills to the test.

I have gotten to the stage where I want to be able to allow the user to add new tasks. I have managed to allow the user to type in a value of their choice and allow it to be posted to the task area. But when I try to call the newly appended tasks to add the functionality that the other non-DOM elements have, I can't seem to make them connect.

I wanted to see how far I could get by doing my own independent research and this is where I have plateaued. I have tried multiple ideas and got to an if statement which in the end I don't think will work either as it doesn't allow me to write another function without an error occurring.

Could someone please explain to me how I can resolve this? Also where I can look to understand the issue?

Here is my CodePen - https://codepen.io/Nathan-Callum-Marshall/pen/pLKbRv

Thanks,

3 Answers

andren
andren
28,558 Points

Rather than adding special code when you add the new element, it is a better idea to change how you attach the event listeners in the first place.

jQuery cannot attach an event listener to an element which does not exist yet, therefore if you have a collection of elements that you know will change throughout the lifetime of your page you should not add event listeners directly to them. Instead you should add the event listener to the element that the new elements will be placed within.

Due to Event bubbling all click events on the new elements will propagate up to the parent elements. Since the parent exists when the page loads and continues to do so as you add (and potentially remove) elements it is the ideal element to attach an event listener to.

You could for example write your click-listener attaching code like this:

$(".task-area").on("click", function(event){ // Attach to .task-area
  var target = event.target; 
  if ($(target).is(':checked')  ){  
  $(target).closest(".task").addClass("checked");  
 }
 else {
    $(target).closest(".task").removeClass("checked");
  }
});

Notice that I use event.target within that code instead of this, this will always point at the element that the event listener is attached to, while event.target points to the element that actually triggered the event.

That code would work, but it would trigger everytime you clicked within the .task-area even when you didn't click on any checkbox, that would not produce any issues but it's somewhat inefficient.

The more efficient alternative is to use the on method with three arguments like this:

$(".task-area").on("click", "input[type=checkbox]", function(event){
  if ($(this).is(':checked')  ){    
  $(this).closest(".task").addClass("checked");  
 }
 else {
    $(this).closest(".task").removeClass("checked");
  }
});

When you use pass three arguments the first will be the event listener type, the second the selector that jQuery will be on the lookout for and the third the actual event listener function. With the above code jQuery will only trigger the method when it detects a click on elements matching the input[type=checkbox] selector. And it will treat said elements as the one the event listener is attached to, so the this keyword can be used.

Both of the code examples above will fix your issue of the new tasks not having the click event affect them.

Hi, Great to see that you are putting new skills into practice, keep going!

This is a very common issue for beginners in JQuery world and JavaScript in general, but don't be afraid it is quite easy to understand, so here is what you are missing.

I looked up to you your code pen project, and I will point out there why it is not working.

You defined three event listeners in your app.

  1. Click listener for add new task button.
  2. Click listener for checkbox inside your task.
  3. Click listener for reset task button.

The issue here is that you have dynamically added an element without a listener. What I mean by that is following:

At the moment your listeners get defined they target and apply only on visible elements, and that's it, your javascript code executed and only those listeners are now active in an event loop and waiting for clicks to be performed.

Here is my suggestion to work with such issue is to update yours on event listener. After reading this take a look at official documentation here for on method.

Instead of targeting input[type=checkbox] you can target parent component which will be .task-area since you will always have this element on page and event listener will be hooked for each click on that area instead of single input[type=checkbox]

That is the first part of the solution, now, JQuery on method accepts "selector" as a second optional argument, so when we click on that parent task area we want to search for input[type=checkbox], so let's modify your current code to work this way.

Line 22: $.checkedFunction = $(".task-area").on("click", 'input[type=checkbox]', function(event) { ...

After this, your code will work properly.

If you want to read more about this refer to the following links:

jquery-adding-event-listeners-to-dynamically-added-elements

jquery-to-pure-js-event-listeners-on-dynamically-created-elements

IMPORTANT NOTE Second link has an expiration on SSL certificate so it alert that it is insecure. If you don't trust that blog post don't go there, personally, I have no problems with it since it is just a text page with no harms, but I have to note.

Hope this helps you understand why your code is not working and you will know in future what to do when you come across the same one.

Keep rocking and happy coding!

Andreas Nyström
Andreas Nyström
8,887 Points

Hi buddy.

I can try to help you a little, but not sure exactly where you need to do these fixes. I've checked your codepen and it seems like you're using $(element).on('click', function(){}) syntax.

You might wanna try the syntax $(document).on('click', element, function(){}). So:

// This is your syntax now.
$("input[type=checkbox]").on("click",function(event){
});

// Try this one: 
$(document).on("click", "input[type=checkbox]", function(event){
});

Please research the benefits of each syntax. Basically the difference is that when you load your app, you're trying to handle a click on something that doesn't exist at the time. Meanwhile, the document always exists. So when you're using $(document).on('click'...) you're actually listening to clicks on the document.

Therefor you can still use this when adding a new item. The other syntax only does it on whatever is on the page when it loads. I'm sorry for terrible explanation. But research this yourself and keep at it.

If you are using this, maybe you should do this on your reset instead?

$.reset = $(document).on("click", '.reset', function(event){ 

  if ($('.task').hasClass("checked")) {

    $(".task").removeClass("checked");
    $(".task input[type=checkbox]").prop("checked",false);
  }
});

Keep at it and good job buddy!