How do you target an element that is dynamically generated? [duplicate] - javascript

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();
});

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..
});

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
});

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.

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'));
});

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

Related

Assign java scripts to cloned HTML element

I have a html div and I clone it using Jquery. That div contains labels and text fields. ids of all of them generated and assigned dynamically. I have no problem with that.
A java script is assigned to a text field of original div. The cloned text fields does not have the javascript assigned to it.
the script I need to assign:
<script>
$(function() {
$("#datepick_onBooking,#datepick_Pay1,#datepick_Pay2,#datepick_totPay,#datepick_deedFees").datepicker();
});
</script>
the script I use to make clones:
<script>
var i = 3;
//When DOM loaded we attach click event to button
$(document).ready(function() {
$('#addAnotherPayment').click(function() {
var cloned = $('.PayDiv0').first().clone();
var noOfDivs = $('.PayDiv0').length+2;
cloned.insertBefore("#totPayForm");
// append count to the ids
cloned.attr('id', 'PayDiv' + noOfDivs);
cloned.find('label').attr('id', 'PayLbl' + noOfDivs);
cloned.find('input[type="text"]').attr('id', 'datepick_Pay'+ noOfDivs);
cloned.find('input[type="number"]').attr('id', 'amount_Pay'+ noOfDivs);
cloned.find('.PayLbl2').html("Payment No " + i++ + ':');
});
});
</script>
datepick_Pay1, datepick_Pay2, datepick_totPay, datepick_deedFees are static elements and they have been assigned to the script. I create text fields using cloning as datepick_Pay3,datepick_Pay4, and so on.
I cannot figure out how to dynamically assign the script to that newly created elements.How can I do that?
A Boolean indicating whether event handlers and data should be copied along with the elements.
change this line.
var cloned = $('.PayDiv0').first().clone(true);
when you clone something especially elements which having events
use parameter as
clone(true)
But this will be harmfull based on how event is attached on the actual element when copying the events to the cloned element may affect the actual.
You need to clone with events. http://api.jquery.com/clone/
var cloned = $('.PayDiv0').first().clone(true);
Then your script needs to be changed to work for dynamic elements. Here as soon as input elements gets focus, asssign the datepicker based on wild card id selector, if it doesn't already have one.
$(function() {
$('body').on('focus',"input[id^=datepick_]", function(){
if(!$(this).hasClass('.hasdatepicker'))
{
$(this).datepicker();
}
});
});

Modifying Content in JavaScript-Generated HTML Code

I am trying to modify the innerHTML of a div when clicked. I have dynamically generated an array of divs, and I want to specifically access the table which the user has clicked.
I have tried dynamically setting the ID of the tables in the JavaScript code:
(for var i=0;i<array.length;i++){
var IDvalue = "foo";
// append table to HTML string.
html += "<div onclick='modifyInnerHTML(\"" + IDvalue + "\")'>...</div>";
var divs = document.getElementsByTagName('div');
divs[divs.length-1].id=array[i].IDvalue;
}
Then in modifyInnerHTML() I access the element by ID:
function modifyInnerHTML(id){
document.getElementById(id).innerHTML+="Add an update";
}
While I think this code should work fine, it is breaking at the document.getElementById(id) function, and I realize the id of the divs is not being set dynamically. Any thoughts on why this might be or are there faster ways to do this?
Thanks in advance!
You'd better use a DOM manipulation library for this, like jQuery.
As for the events, jQuery will let you define them in a much more reliable way. You should avoid defining event handlers in attributes anyway, better attach them to the DOM using references to elements, or, better yet, jQuery elemnt sets.
Case 1: Generate some divs dynamically with an event handler already set:
for(var i = 0; i < 10; ++i) {
$("<div>")
.addClass("clickable-div")
.html("click me!")
.on("click", function() {
$(this).html("You clicked me!");
})
.appendTo("body");
}
Case 2: Add an event handler to all divs that contain the class clickable-div
$("div.clickable-div").on("click", function() {
$(this).html("You clicked me!");
});
jQuery is much faster to get things done with than anything you'd write in pure JS.

Dynamically adding onchange function to drop down with jQuery

I have a couple of drop down boxes with ids country1, country2, ... When the country is changed in a drop down the value of the country shoudl be displayed in an alert box.
if I add the onchange handler for one box like this it works fine:
$('#country1') .live('change', function(e){
var selectedCountry = e.target.options[e.target.selectedIndex].value;
alert(selectedCountry);
});
But I need to do this dynamically for all drop down boxes so I tried:
$(document).ready(function() {
$('[id^=country]') .each(function(key,element){
$(this).live('change', function(e){
var selectedCountry = e.target.options[e.target.selectedIndex].value;
alert(selectedCountry);
});
});
});
This doesn't work. No syntax error but just nothing happens when the seleted country is changed. I am sure that the each loop is performed a couple of times and the array contains the select boxes.
Any idea on that?
Thanks,
Paul
The reason .live() existed was to account for elements not present when you call the selector.
$('[id^=country]') .each(function(key,element){ iterates over elements that have an id that starts with country, but only those that exist when you run the selector. It won't work for elements that you create after you call .each(), so using .live() wouldn't do you much good.
Use the new style event delegation syntax with that selector and it should work:
$(document).on('change', '[id^=country]', function(e) {
// ...
});
Replace document with the closest parent that doesn't get dynamically generated.
Also, consider adding a class to those elements along with the id attribute.
Instead of incremental ids I'd use a class. Then the live method is deprecated but you may use on with delegation on the closest static parent or on document otherwise.
$('#closestStaticParent').on('change', '.country', function() {
// this applies to all current and future .country elements
});
You don't need an each loop this way; plus events are attached to all the elements in the jQuery collection, in this case all .country elements.

Get the id of a the item that is clicked

I have this html code:
<b class = "edit" id = "foo1">FOO</b>
<b class = "edit" id = "foo2">FOO2</b>
<b class = "edit" id = "foo3">FOO3</b>
And I have this code in jQuery:
$('b.edit').click(function(){
//GET THE ID OF THE b.edit: e.g foo1, foo2, foo3
$('.editP').focus();
});
How can I get the id value of the b.edit, as there are multiple instances of b.edit, and I want to get the specific id of the one clicked? How can I do this?
Thanks, Sorry, I am pretty new to javascript.
I'm assuming from your sample code that you're using jQuery? If so you can get the id as follows:
$('b.edit').click(function(){
this.id;
});
EDIT:
The direct reference to the attribute is indeed more efficient if all that is required is simply the id.
Also can be obtained from the jQuery object:
$('b.edit').click(function(){
$(this).attr('id');
});
Sample fiddle: http://jsfiddle.net/5bQQT/
Try with this:
$('b.edit').click(function(e){ //When you use an event is better
//send the event variable to the
//binding function.
var id = e.target.id; //get the id of the clicked element.
/*do your stuff*/
$('.editP').focus();
});
try this. You can use keyword "this" to retrieve the attr ID...
$('b.edit').click(function(){
alert($(this).attr("id"));
});
$('.edit').click(function(){
var theId = $(this).attr('id');
}
This will get you the ID of anything clicked with a class of .edit
$('.edit').live('click', function() {
alert( this.id );
});
Sample
http://jsfiddle.net/ck2Xk/
When passing a click handler in JQuery, you actually have a reference to something called an event object. This event object has a property called target, which is a reference to the element that was clicked.
$('b.edit').click(function(eventObject){
eventObject.target // this is the element that was clicked.
});
Since you have a reference to the target element, you can do whatever you like. In this case, you could just access eventObject.target.id.
Since nobody has shown the simplest method yet that doesn't even need jQuery to get the id:
$('.edit').click(function() {
alert(this.id);
});
I never understand why people use jQuery for getting simple attributes which involves two jQuery function calls (and a bunch of overhead to create a jQuery object) instead of one direct attribute reference.
something like this:
var id = $(this).attr('id');
More clearly:
$('b.edit').live('click', function(){
var id = $(this).attr('id');
// in this scope this.id works too
// var id = this.id;
});
This is called event delegation in Javascript. More info can be found in Zakas blog http://www.nczonline.net/blog/2009/06/30/event-delegation-in-javascript/
The idea in few words is you attache the event to a parent node and then waiting for some event on the child node. In the example below I attach the onclick event to the document itself. Then inside the event handler you will write a switch statement to check the clicked element id, then do what you want to do for that element
document.onclick = function(event){
//IE doesn't pass in the event object
event = event || window.event;
//IE uses srcElement as the target
var target = event.target || event.srcElement;
switch(target.id){
case "foo1":
foo1();
break;
case "foo2":
foo2();
break;
case "foo3":
foo3();
break;
//others?
}
};
//some dummy handlers
var foo1 = function(){
alert("You clicked foo1");
};
var foo2 = function(){
alert("You clicked foo2");
};
var foo3 = function(){
alert("You clicked foo3");
};
For how to implement event delegation in jQuery you can check http://api.jquery.com/on/#direct-and-delegated-events
Even though this is not a real answer to your question. I will try to explain why what your asking is not the way to go. Since you are new especially, since learing bad practices could be hard to unlearn. Allways try to search for an ID before finding an element by its Class. Also try to avoid giving every element the same class (and in this case ID to), just give it an encapsulating parent.
Furthermore, the id of an element is really specific and should preferably used to find / select / bind events to. An id should usually be unique for this to work, so in your case a couple of things could be optimized, lets say like:
<div id="foo">
<b id="1">Foo</b>
<b id="2">Other foo</b>
<b id="3">Some foo</b>
</div>
Now if you want to know which was clicked there are multiple ways to accomplish it, but a nice one is simply binding a parent its children (i.e <div id="foo"> .. </div>). This way you can alter the structure of your pretty fast, without changing all the classes and id's.
With jQuery you can get the attribute id using the .attr() function. However I told you the id was pretty specific and thus has its own rights in javascript world. An id can also be directly targeted ('DOMelement.id', but this would be too much to explain for now)
In two ways the <b> can be targetted:
Example a)
var b_elements = $("#foo").children();
Example b)
var b_elements = $("#foo").find('b');
We can add jQuery (or javascript events) to these found elements. The nice thing about jQuery is that it simplifies alot of work. So in your case if you would like to know an id of a certain clicked <b> field you could use a very verbose way:
b_elements.click(function()
{
var clicked_element = $(this);
alert(clicked_element.attr('id'));
});
Verbose because you can do it much much shorter, but who cares about a few bytes when your learning and this makes remembering functions and events alot easier. Say you wanted to get the class edit by finding the where you knew the id that was clicked:
b_elements.click(function()
{
var clicked_element = $(this);
alert(clicked_element.attr('class'));
});
And to conclude, the id of an element is ment to be unique because it makes searching through big documents alot faster. Also don't forget to look and learn plain javascript, as it helps coding in jQuery alot too, but not the other way around. Your given question would require a for loop in plain javascript since it cannot do a lookup by class nor id nor have they have a common parent.
Good luck with learning :)

jQuery: if hovering over an element injects something into the DOM, can I still reference it?

If hovering over an element injects something into the DOM, can I still reference it?
Or do I have to use the live plugin?
I'm using jQuery 1.3.2
i.e. can I do
$("#someItem").attr("src", "htt...")
on it?
I am trying to do it, but I think its not working b/c its a newly added item to the DOM.
Yes, an element that has been added to the DOM can be selected and referenced.
Or, if you already had a reference to it that you used when you added it to the DOM, you can continue to use that reference after it has been added as well.
Using this example, you can see that you can both use a current reference to a newly created element, as well as make a new reference to it.
http://jsfiddle.net/Czuvx/
HTML:
<div id='button'>hover me</div>
jQuery:
$('#button').hover(function() {
$('#newElement').remove();
var $myNewElement = $('<div id="newElement">new Element</div>');
$('body').append($myNewElement);
$myNewElement.css({color:'red'});
},
function() {
// This function has completely different namespace
// from the one that created and inserted #newElement
// and I can get a reference to it just like any other element
var $newReferenceToElement = $('#newElement');
$newReferenceToElement.css({color:'blue'});
});
Showing a bit more of your code would be helpful, but I think I get the general idea.
If you're just looking to add events or something to that item, you can do it before you append the item.
(function($){
$(function(){
$("#link").hover(
function(){
var $div = $("<div class='inserted_div'></div>").bind("click",function(){ ... });
$("body").append($div);
}),
function(){
});
});
})(jQuery);
So just bind the events or attributes at the time of creation, before you append it.

Categories