So I have built one page that all the data gets pulled into. Works great in IE9+ and chrome but need it to work in IE8 and anything that is pulled in through ajax wont work. Code would be something like this.
ajax
$.ajax({
url: "includes/myfile.php",
type: "GET",
data: ({'data' : data,}),
success: function(data){
$("section").append(data);
}
});
JS
function myfunction(data){
//do something
}
HTML
< button onclick='myfunction(data)' > click here < /button>
Note: I know $(something).on(stuff,stuff) will work but that would involve rebuilding all my functions. so trying to avoid that if I can.
It is because jQuery /JavaScript is unaware of the items that are loaded in myfile.php. The easiest solution is to use on() to delegate the events there, so those events will bubble up the DOM tree.
http://api.jquery.com/on/
For instance -
$(document).on('click', 'element', function() {
Now, when element is clicked the click event bubbles up to document where it will be acted on. The element that the event bubbles up to must exist at the time your jQuery code originally runs so jQuery is 'aware' of the element and can intercept bubbled events to that element. That makes document a fairly safe bet, but you can narrow it down if you desire.
If you don't want to go the easier route you can write event delegation in vanilla JavaScript:
// get the parent element, add a click listener...
document.getElementById("element").addEventListener("click", function(e) {
// example using a list item
if(e.target && e.target.nodeName == "li") {
console.log("list item ", e.target.id.replace("post-"), " was clicked!");
}
});
Related
There are few elements on our DOM which are loaded as a response to a webservice.
I want to bind click event on them.
I do not have any control on webservice call, as it is done by a framework I am not intending to modify.
$(document).on('click', 'element', function)
This would have helped me but the jquery version that is being used is older.
Is there an alternative or native javascript solution to this?
One of the hot methodologies in the JavaScript world is event delegation, and for good reason. Event delegation allows you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent. Refer this: http://davidwalsh.name/event-delegate
document.getElementById("parent-list").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
if(e.target && e.target.nodeName == "LI") {
// List item found! Output the ID!
console.log("List item ", e.target.id.replace("post-"), " was clicked!");
}
});
I'm using the jQuery Mobile option allowSamePageTransition, which enables me to go from
page A > page A > page A ...
I need this to allow browsing through a catalogue of items. My problem is, the items need some form of interaction and I used to attach the interaction binding to document, because it is set before the elements affected are generated.
However, reloading the same page over and over again will re-bind my event handlers every time I reload.
My first idea was to use .off when the page is being hidden, but reloading a page #foo, will trigger pagehide on the same page being shown, so all bindings set on
$(document).on("pagebeforeshow.foo_events", "#foo", function(e) {
// bind when shown
});
will be unbound again by the previous #foo being hidden
$(document).on("pagehide", "#foo", function (e) {
$(this).off(".foo_events");
// removes bindings on #foo being hidden AND shown
});
The only solution I have come up with is plastering the document with classes, which I don't like doing:
priv.setBindings = function (param) {
var doc = $(document);
doc
.filter(function() { return $(this).is(".e_gallery") !== true; })
.on("pagebeforeshow.gallery", param.pageId, function (e) {
doc.addClass(".e_gallery");
// run stuff
});
};
But I'm no fan of attaching classes to the dom.
Question:
Is there a way to prevent multiple event bindings set on $(document) when going to the same page over and over again WITHOUT toggling classes?
Solution 1
Best solution would be to use pageinit to bind events. If you take a look at an official documentation you will find out that pageinit will trigger ONLY once, just like document ready, so there's no way events will be bound again. This is best solution because you don't have processing overhead like when removing events with off method.
Working jsFiddle example: http://jsfiddle.net/Gajotres/AAFH8/
Of course this will fail in case multiple HTML solution is used.
Solution 2
Remove event before you bind it:
$(document).on('pagebeforeshow', '#index', function(){
$(document).off('click', '#test-button').on('click', '#test-button',function(e) {
alert('Button click');
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/K8YmG/
Solution 3
Use a jQuery Filter selector, like this:
$('#carousel div:Event(!click)').each(function(){
//If click is not bind to #carousel div do something
});
Because event filter is not a part of official jQuery framework it can be found here: http://www.codenothing.com/archives/2009/event-filter/
This is probably best solution because event is going to be bound ONLY once.
Solution 4
Probably an easiest of them all.
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#test-button',function(e) {
if(e.handled !== true) // This will prevent event triggering more then once
{
alert('Clicked');
e.handled = true;
}
});
});
Working jsFiddle example: http://jsfiddle.net/Gajotres/Yerv9/
This is a 180 percent different solution then solution 3, in this case event is going to be bound numerous times but it will be allowed to execute only once.
More info
If you want to find more about this problem take a look at this article, working examples are included.
I've a simple application, and I decided to use ajax to load levels for simplicity / whatever reason (maybe to learn a bit).
But I'm stuck...
$.ajax({
url: "actions.php",
get: "GET",
data: "show_level=" + 1,
cache: false,
success: function (views){
$(".slides_container").append(views);
}
});
The problem is, views appended to my container is not selectable anymore, basically all jquery functions I had stopped working alltogether.
What is happening?
If you are using bindings like $(".target-element").click(function(){ do something here}); they are only valid for elements already in the DOM when the binding happens.
You would need to use $("#element-already-in-dom").on("click", ".target-element", function(){do something here});
You are a victim of non event bubbling.
When you bind an event to an element you typically do this on window load. If an element is added to the DOM after window load, the event will not be bound to it, despite it meeting all other conditions as laid out by your event handler.
Instead, you must use delegation, this means that events are bound to non changing elements on the page and then bubble up to the correct elements.
$('.appended-view').click(function(event) { ... }
Will not work
$('body').on('click', '.appended-view', function(event) { ... }
Will work
EDIT: The Issue has been solved, as it turns out, the Select2 library had a custom command for this typa thing:
$("#element").on("change", function (e) { ... }
// Defined as "change"
I'm using a dropdown menu library called Select2 3.2. In short, the code takes a bunch of select and option tags, and generates a cool drop down search list.
However, after the site is rendered; when I click 'view source', all my select and option tags are still there, but when I right click the fancy new generated menus themselves and select "inspect element" (using google chrome), the html is TOTALLY different.
I think that this is causing the problem, all this new code is rendered from the custom library's JS, and after my jQuery event commands.
Specifically, here is my command:
$(document.body).on('click', '.select2-result-label', function() {
var name = $(this).text();
var post_to = '/myurl/';
$.post(post_to, { dat: dat},
function(response) {
...
}, 'json'
)
I believe the on() method takes care of this kinda stuff but apparently not, any help would be appreciated!
RELEVANT EDIT:
Here is a blurb from another Stack Overflow post:
The view page source page shows you the exact text that
was returned by the server.
Inspect element actually shows you the fully rendered DOM tree.
Knowing that, maybe solving this will be easier.
Here is a JS Fiddle related:
http://jsfiddle.net/JpvDt/47/
Try to make the alert "worked" appear when you click on an "x" in the multi bar.
Right now my code has it to register the class which contains the x's.
$(document.body).on("click", ".select2-search-choice-close", alert("worked"));
Scenario 1:
Your problem is may be you bind on method for whole DOM which is really BAD. So always try to bind that to the closest div (closest parent element) which your controls are exist.
About Event performance from Jquery API says like below.
Attaching many delegated event handlers near the top of the document
tree can degrade performance. Each time the event occurs, jQuery must
compare all selectors of all attached events of that type to every
element in the path from the event target up to the top of the
document. For best performance, attach delegated events at a document
location as close as possible to the target elements. Avoid excessive
use of document or document.body for delegated events on large
documents.
Scenario 2:
Call your on event like below (with off event).
$(#yourElement).off('click').on('click', '.select2-result-label', function() {
var name = $(this).text();
var post_to = '/myurl/';
$.post(post_to, { dat: dat},
function(response) {
...
}, 'json'
)
I hope this will help to you.
As it turns out, the Select2 library had a custom command for future changes to the toolbar.
Read more here: http://ivaynberg.github.com/select2/#programmatic
It's vital to note that many standardized jQuery calls won't work with Select2, you must use their custom set-up.
$("#element").on("change", function (e) { ... }
// Defined as "change"
Just replace $(document.body) by $(document)
I have a jQueryMobile site/app where performance is an issue. I am reading a lot about how it's smart not to bind too many separate handlers. So if you have a page with a lot of buttons , the advice is to bind like this...
$(document).on('click',function(){
if (this = $('#button1')){
//Handler for button one
} else if (this = $('#button2') {
//etc
} else //etc
})
...rather than like this...
$('#button1').click(function(){
//Handler for button one
})
$('#button2').click(function(){
//Handler for button two
})
//etc
So I am wondering to what extent this is truly useful.
What if I made one listener for all 'pageshow' events in my document? (a jQueryMobile website is a single document containing many pages, and many of those pages need a bit of dolling up around showtime).
What if I made one click listener for all forty-odd buttons in the document, and used the handler to distinguish which button we're dealing with and what needs to be done in response?
Your first option is faster to install and initialize, but slower to run when an event happens.
If you had hundreds of buttons with all nearly identical event handling, it might make sense to only install one event handler for all of them rather than run the code to install hundreds of event handlers. But, you would still pay a small performance penalty when a particular event happens.
If you want to maximally optimize for run-time performance at the time of an event, it is still faster to install an event handler on the specific object you want to monitor. That's because the event handlers are kept in a separate list just for that object and the code doesn't have to sort through a long list of event handlers to find which one is appropriate for that specific object and event.
Also, your if statement in the first option will never work for several reasons. It would need to be something like this:
$(document).on('click',function(e) {
if (e.target.id == 'button1') {
//Handler for button one
} else if (e.target.id == 'button2') {
//etc
}
})
And, anytime you use delegated event handling, it's better to pick a common parent for the buttons that is much closer to the actual objects than the document object (helps runtime performance).
$("#buttonContainer").on('click',function(e) {
if (e.target.id == 'button1') {
//Handler for button one
} else if (e.target.id == 'button2') {
//etc
}
})
If you wanted just button clicks with delegated event handling, you could use some of the delgation features built into .on() like this
$("#buttonContainer").on('click', 'button', function(e) {
if (this.id == 'button1') {
//Handler for button one
} else if (this.id == 'button2') {
//etc
}
})
The advice is, to use event delegation. You don't actually need to bind that "master event handler" to the document or document.body, you can (and should) bind it to the closest possible node that all buttons share.
$('#ClosestSharedParent').on('click', 'button', function( event ) {
// "this" references the button that was actually clicked
switch( event.id ) {
case 'button1':
alert('button1 clicked');
break;
case 'button2':
alert('button2 clicked');
break;
// and so on
}
});
The second argument from .on() accepts a selector, where you can specify which elements you want to delegate events for. In older version of jQuery, this was accomplished by the .delegate() method.
Ref.: .one(), .delegate()