I created simple fidlle
var cnt = 1;
function add() {
var root = document.getElementById('root')
root.innerHTML += '<br /><a id= "a_' +cnt + '" href="#">click</a>'
var a = document.getElementById("a_"+cnt)
a.addEventListener('click', function(event) {
alert('click:a_'+cnt)
})
cnt++
}
When Add button is clicked once new link is added and after clicking on this link alert appears.
When more links are added with Add button only the last link works(others does not have click event listener according to devel tools).
Why does only the last link work and how can I make all links working?
Because you are reinserting the anchor tags in the html.
The question is similar to Appending HTML string to the DOM.
You can use
root.insertAdjacentHTML( 'beforeend', '<br /><a id= "a_' +cnt + '" href="#">click</a>');
instead of
root.innerHTML += '<br /><a id= "a_' +cnt + '" href="#">click</a>'
Working fiddle https://jsfiddle.net/0nm4uLvd/
Just to improve answer, here is another reference why event listeners are removed when dom element is removed => If a DOM Element is removed, are its listeners also removed from memory?
thanks to these guys :)
You're modifying the innerHTML of your root element. This will cause the complete 'root' to be destroyed en recreated, so only the new event will work.
See Manipulating innerHTML removes the event handler of a child element?.
You can set a class to your links: class="some-class".
Then you can use jquery to listen to click event on elements of this class.
$(document).on('click', '.some-class', function(event) {
alert('click:'+$(this).attr('id'));
});
Runnable example https://jsfiddle.net/2d99hq1h/1/
Check in the console your variable cnt.
You did not post the whole context where the function add is called, but I have a strong guess that this variable stays always 1.
And write a semicolon after your cnt++
For the possible benefit of anyone who finds this page many years after the initial question was asked:
The culprit that destroys existing event listeners seems to be
.innerHTML +=
so use a different technique.
For example:
HTML Insertion Technique 1 (which inserts the HTML but also inadvertently seems to erase any existing event listeners on other unrelated elements, so is NOT recommended):
document.body.innerHTML += '<div id="something"</div>';
Technique 2 (which works and does not affect existing event listeners):
document.body.insertAdjacentHTML( 'beforeend','<div id="something"</div>');
...or any other way (such as with append and so on).
Related
I have a simple js that outputs html based on a vendors variables
if (icAnalytics == "1"){//Analytics
$("#anal22").html("<a class='test1 test2 test33' href=/dashboard/site_sum.asp?id=application>Analytics</a>");
};
if (icPermissions >= "1"){//Publishers
$("#pub22").html("<a tabindex='0' href=/admin/default.asp class='ubermenu-target ubermenu-target-with-icon ubermenu-item-layout-default ubermenu-item-layout-icon_left'><i class='ubermenu-icon fa fa-lock'></i><span class='ubermenu-target-title ubermenu-target-text'>Pub</span></a>");
}
if (icPermissions == "2"){//Admins
$("#admin22").html("<a class=aTop2 href=/system/default.asp>Admin</a>");
}
else {
};
The problem is when I had the html to a "li" - so <li id="pub22"> it automatically closes the "li" even though I haven't added that code into it. I can't really change the layout of the page as I don't have access to it. Is there a way to keep the li from closing after inserting the html from javascript?
Note - This is a little bit more complex. The pub22 li is the first and then the anal22 and admin22 are nested and have different perms. Since they are nested I wanted to leave the li open. Maybe I am making this too hard.
As soon as you add any HTML to the DOM with JavaScript, the web browser is going to try to parse that HTML. If you create an <li> element without closing it, the browser is gonna be like "whoa, that's not valid HTML; I'll just fix that" and it'll automatically close the tag.
But all hope is not lost! Instead of adding code to the DOM as you write it, store it all in a string and only add the string to the DOM once you're done with it.
Here's an example:
var myHtml = "<li>"
myHtml += "blah blah this is some content";
myHtml += "</li>";
$("#someElement").html(myHtml); //we add the html to the DOM only now that we're done writing it
What you need to do something like:
$element = $('<li id="pub22">...</li>');
$element.append('<a id="anal22" href="...">...</a>');
$element.append('<a id="admin22" href="...">...</a>');
$element.appendTo('#someContainerElement');
Here you create your <li>, append a few <a> elements to it, and then finally attach the <li> to some existing element in the DOM. Creating elements in this way and attaching them to DOM when you are ready to make active is one of the key features of jQuery (in fact this is part of the base jQuery function).
jQuery's .html uses JavasScript's .innerHTML
.innerHTML inserts nodes into the DOM. A node, by definition, has to be valid markup. So the browser is correcting your bad markup on the fly.
I have an AJAX call that when it's done i have this code:
$(".results").append('<div class="horizontal result_element"><div class="result_photo"></div><div id="'+user_id+'" class="result_data">'+user_name+'</div></div>');
Later i want something to happen when i click on the class result_element:
$(".result_element").click(function(){
var url = "profile.php?user_id="+$(this).children("[class='result_data']").attr("id");
$(location).attr('href',url);
});
But it doesn't work and my thought is that jQuery create the html elements but doesn't appends them to the DOM.Any idea on how can i make this work with that method?
I assume that you mean with 'later' the time in the user-sight an not the time in the script.
The problem is that the jQuery doesn't know about the element if you create it after explaining that jQuery shell do x on event y. So if you set the click-event in $(document).ready(function(){*here*}) and you create an element afterwards (after the document-ready was fired), jQuery doesn't know these fresh elements.
So to solve your problem, try to add the event after you created the element (creation not equal to appending!):
// created the element
var newElement = $('<div class="horizontal result_element"><div class="result_photo"></div><div id="'+ user_id +'" class="result_data">'+ user_name +'</div></div>');
// now set the event
newElement.click(function () {
var url = "profile.php?user_id="+ $(this).children("[class='result_data']").attr("id");
$(location).attr('href',url);
})
// now append it
newElement.appendTo($(".results"))
// or: $(".results").append(newElement)
And you can reorder the two last steps, so you first append it and then set the event, thats not the point. The point is, that you create the element first and then set the event.
I believe, click is not working on result_element class which is added dynamically. Try with following code snippet.
$(document).on("click",".result_element", function(){
var url = "profile.php?user_id="+$(this).children("[class='result_data']").attr("id");
$(location).attr('href',url);
});
jQuery + JavaScript + Rails 4
prefix = "onward_"
json_data = {"367278":
{"bus_schedules":
{ "id": 367278,
"origin_id": 134,
"destination_id": 506
},
"drop_points": null,
"board_points": null,
"operator_name": "ABC"
}
}
json_data1 = JSON.stringify(json_data);
html = '<a href="#" id="'+prefix+'active_travel_filter_'+
operator_ids[i]
+'"onclick="removeTravelFilter('
+'\''+prefix+'\''+',\'travels\''+',\''
+json_data1+'\',\''+json_data1+'\')"
value="'+operator_ids[i]+'">'
+getOperatorName[operator_ids[i]]+'</a>'
console.log(html);
$("#active_fiters_blk").append(html);
//console.log output
ABC
But while append to the div I am getting this format, but it should be above format.
<a value="33" group)"}}')"="" group)"}}','{"367278":{"bus_schedules":{"id":367278,"origin_id":134,"destination_id":506},"drop_points":null,"board_points":null,"operator_name":"sre="" booking(ananth="" 367278":{"bus_schedules":{"id":367278,"origin_id":134,"destination_id":506},"drop_points":null,"board_points":null,"operator_name":"sre="" onclick="removeTravelFilter('onward_','travels','{" id="onward_active_travel_filter_33" href="#">ABC</a>
It should be an inline script only because I want each individual onclick event.
The HTML you're trying to insert, is this string:
0
When you place that into the DOM, your browser will be confused by the parameters of the onclick part: onclick="removeTravelFilter('onward_','travels','{" That last quote (") there will be interpreted as the end of the onclick parameter.
If you switch around the quotes in your JavaScript like this:
html = "<a href='#' id='"+prefix+"active_travel_filter_"+operator_ids[i]+"' onclick='removeTravelFilter("+"\""+prefix+"\""+",\"travels\""+","+json_data1+","+json_data1+")' value='"+operator_ids[i]+"'>"+getOperatorName[operator_ids[i]]+"</a>"
Then you should be fine:
<a href='#' id='onward_active_travel_filter_0' onclick='removeTravelFilter("onward_","travels",{"367278":{"bus_schedules":{"id":367278,"origin_id":134,"destination_id":506},"drop_points":null,"board_points":null,"operator_name":"SRE Booking(Ananth Group)"}},{"367278":{"bus_schedules":{"id":367278,"origin_id":134,"destination_id":506},"drop_points":null,"board_points":null,"operator_name":"SRE Booking(Ananth Group)"}})' value='0'>0</a>
I'm not saying this is the best way to pass those parameters to your function, but it works.
I'd maintain a dictionary associating anchor id names with their corresponding json data.
window.dataCache = {
"onward_active_travel_filter_90": {...},
...
}
Once element clicked I'll fetch the required json object.
$('a').click(function(){
var id = this.id;
var jsd = dataCache[id];
//pass to target function
foo(jsd);
});
Now if the anchor is added a little late into the page dom, I'd have to take care about attaching event handlers appropriately.
In jquery, we can just work with the .on() handler.
Explanation:
Well, we normally do something like $('element').click(function(){...});. This is usually executed in the jquery dom ready event:
$(function(){
$('element').click(function(){...});
});
The stretch of code in the dom ready event is executed once the DOM is ready for jquery consumption. Hence the click event will get attached to any element that exists in the DOM at that point of time.
Any subsequent addition of element into the web page, the click event handler will not get attached to it.
But we'd want such a functionality!
Hence we have to manually take care of it. Meaning create the element wire the event click handler appropriately, and then add it to DOM.
An alternative to this we have the jQuery .on() method. However, it functions differently from whats is described above. It listens for the click event which "bubbles" up on a target container.
Please read the docs of .on() to get a better idea.
quick question, i know we can change the content of a
<div id="whatEverId">hello one<div> by using:
document.getElementById("whatEverId").innerHTML="hello two";
now, is there a way I can ADD stuff to the div instead of replacing it???
so i can get
<div id="whatEverId">hello one hello two<div>
(using something similar of course)
<div id="whatever">hello one</div>
<script>
document.getElementById("whatever").innerHTML += " hello two";
</script>
Notice that using element.innerHTML += 'content' would empty inputs and textareas to their default, blank state, unclick checkboxes, as well as removing any events attached to those elements (such as onclick, on hover etc.) because the whole innerHTML would be reinterpreted by the browser, which means .innerHTML is emptied and filled again from scratch with the combined content.
If you need to keep the state, you'd need to create a new element (a <span> for instance) and append it to the current element, as in:
let newElement = 'span'
newElement.innerHTML = 'new text'
document.getElementById('oldElement').appendChild(newElement)
document.getElementById("whatEverId").innerHTML = document.getElementById("whatEverId").innerHTML + "hello two" + document.getElementById("whatEverId").innerHTM ;
What jcomeau_ictx suggested is an inefficient way of editing the innerHTML.
Check Ben cherry's PPT http://www.bcherry.net/talks/js-better-faster
The correct way will be detaching the element and making changes to it and then appending it back to the parent node.
Use https://gist.github.com/cowboy/938767 Native javascript from this gist to
detach element.
If you are appending, you can just change your = to a +=
document.getElementById("whatEverId").innerHTML += 'hello two';
If prefixing
document.getElementById("whatEverId").innerHTML = 'hello two' + document.getElementById("whatEverId").innerHTML;
Although I would highly recommend using jQuery or MooTools javascript libraries/frameworks to do this sort of thing. If you're adding tags not just text nodes, then you should use the DOM createElement or one of the aforementioned libraries/frameworks.
You can do it by appending div string like this..
document.getElementById('div_id').innerHTML += 'Hello Two';
Yes I have see the post here
And I tried that but the problem is, my jquery object looks more like this:
var $foo = $('<ul><li id="' + line.id + '" label="' + label + '" rel="file">' + line.title + '</li></ul>');
$foo.click(function() { openLink(line.url) });
$foo.appendTo($myDiv);
When $myDiv is fully populated I can do this:
var html = $('<div>').append($('#foo').clone()).remove().html();
And I will see all of the lovely HTML, but I don't know if the click stuff will be preserved. See, I want to save the entire DOM modification to localStorage so I can retrieve it quickly since it's pretty static. I need to be able to store it and all its attributes, then yank it back out and restore it, clicks and all.
Does that make sense?
The only way to do this would be to use inline event handlers, which is a bad (and slow) idea.
Instead, you can convert all of your event handlers to live handlers; they will then automatically apply to all matching elements without having to rebind them after changing the DOM.