19

Beginner to all of this, playing around with Firebase. Basically, I want to retrieve text entries from Firebase and have an "Approve" button next to it. When the button is clicked, I want that specific text entry to be pushed to a new Firebase location and the text removed from the page. I am creating the button and the text dynamically and I am having some trouble with selecting the button and the divs I created. I know I have to use on() but I'm unsure of how to use it.

Thanks!

approveRef.on('child_added', function(snapshot) {
 var posts = snapshot.val();
 $('<div id="post">').text(posts.text).append('<button style ="button" id="approve">Approve</button>').appendTo($('#feed'));
});

$('#approve').on("click", function(){
    var text = $('#post').val();
    postsRef.push({'text':text});
    $('#post').remove();

});
Sam
  • 193
  • 1
  • 1
  • 4

5 Answers5

40

You have to bind .on() on a container of your dynamically added element that is already on the page when you load it, and have it like this:

$('#yourContainer').on('click', '#approve', function(){
    //your code here..
});
nix
  • 3,262
  • 2
  • 21
  • 36
  • 3
    To expand, the first argument to on() is the event, the second is a "selector" which, if present, delegates the events to children of this element, even if they are added in the future – Kato Jul 10 '13 at 02:21
  • This worked for me after spending 3+ hours looking for this hack! You sir deserve a medal! – juanchod Oct 03 '19 at 18:02
  • Now, how do you do that if you have a bunch of links, and you need to .each them? – gillespieza Jul 06 '21 at 09:01
16

Your .on() didn't work, because you are adding the button dynamically. You can't find the dynamically added elements directly using that elements id selector like $('#approve'). So you should bind .on() with $(document) selector. This will always contain your dynamically added elements.

$(document).on( eventName, selector, function(){} );

$(document).on('click','#approve',function(){
//your code here
});
Community
  • 1
  • 1
Keerthi
  • 525
  • 8
  • 14
5

I find a quick dip into the DOM, and then running back into jQuery very handy for this problem:

// Construct some new DOM element.
$(whatever).html('... id="mynewthing"...');

// This won't work...
$("#mynewthing")...

// But this will...
$(document.getElementById("mynewthing"))...

This works by turning the DOM object directly into a selector. I like it because the approach is transparent in operation/intent.

Shaheed Haque
  • 644
  • 5
  • 14
2

Another alternative, simpler to understand, less powerful, also perfectly valid, is to simply bind the event while you create the element:

approveRef.on('child_added', function(snapshot) {
 var posts = snapshot.val();
 var $button = $('<button style ="button" id="approve">Approve</button>');
 $button.on("click", function(){
    var text = $('#post').val();
    postsRef.push({'text':text});
    $('#post').remove();
 });

 $('<div id="post">').text(posts.text).append($button).appendTo($('#feed'));
});

Another problem you are going to run into, assuming there will be more than one of these on a page, is that you are using IDs in the records. They're going to clash if they aren't unique.

A great alternative is to refer to these items with data-* tags or other identifying characteristics, such as css tags. But in your case, you don't need them at all!

approveRef.on('child_added', function(snapshot) {
 var posts = snapshot.val();
 var id = snapshot.name();

 var $button = $('<button style="button">Approve</button>');
 $button.on("click", function(){
    // use parent.closest(...) in place of an ID here!
    var text = $(this).parent().closest('textarea').val();
    postsRef.push({'text':text});
    $(this).parent().remove();
 });

 /* just an example of how to use a data-* tag; I could now refer to this element using:
    $('#feed').find('[data-record="'+id+'"]') if I needed to find it */
 $('<div data-record="'+id+'">').text(posts.text).append($button).appendTo($('#feed'));
});
Kato
  • 40,352
  • 6
  • 119
  • 149
  • I don't agree that this is simpler to understand, and it seems unnecessarily complex when binding the .on() command correctly will work just fine. – Colin R. Turner Jan 07 '19 at 11:26
1

I don't sure exactly what are you looking for. You can use .find() to select dynamically elements. I think .find() will look at the html structure again to get needed elements.

$("#button").click(function(e){
   $(".parentContainer").find(".dynamically-child-element").html("Hello world");
});

Or

$(".parentContainer").find(".dynamically-child-element").html("Hello world"); // not in click event

So this is my demo

QDinh
  • 404
  • 4
  • 7