I don't even know where to begin. I'm using Kendo Grid to list data sourced from a server. Everything is fine on first load including when I add additional functions and dom elements in the dataBound function. Calls to the server seemingly update (sync) the Grid just fine. BUT, it seems the dataBound function is called an additional time the second time round. Performing an on click function coded in the dataBound performs it a total of 4 times. How do I test for where the issue is and what do I need to destroy to stop this infuriating behaviour?
I don't even know what code to give you save for pasting in my whole website. What is the underlying theory behind this behaviour because there's obviously something I am fundamentally missing about how javascript, and therefore Kondo, works? How do I test for this, please. Thanks!
A quick solution might be to use off() then on() in the databound e.g.
$(".cell").off("click").on("click", function(e){ ... });
this will get rid of previously attached handlers and ensure you only have one.
Even better, use event delegation outside of the Grid generating code.
$(document).on("click", ".cell", function(e) { ... });
With event delegation, the target of the event does not have to exist at the time the event handler is setup. In the example above, the click is on the document object which already exists, but the handler will only fire if an element with the class 'cell' is actually clicked. You can define this handler once in the document.ready before the grid is even created.
Related
Hi I'm developing my view in JS and I'm stuck in binding a click handler for my horizontal layout element. I've tried using Jquery
$("#myHorizontalLayout").bind("click",function(){window.alert()});
Which didn't work then I tried using attachPress with the element which obviously didn't exist. Please help.
Update:
The JS view is the default view of the application.
When on/bind does not work, it could be that the HTML of the control has actually not been created yet at this point in time. But even if you delay the binding, the re-rendering (re-creation of the HTML after changes) would remove your listener, at least when bound on the control itself.
A proper way of doing this is using the generic attachBrowserEvent function available on every control (here: on the layout) which internally handles all the rendering/rerendering stuff, see this example:
http://jsbin.com/hijutunefi/1/edit?html,output
attachBrowserEvent works for any browser event, as it attaches a new browser event listener to the root node of the control. For the most common browser events UI5 does event delegation, so for the "click" event and several others addEventDelegate can also be used, as pointed out by aborjinik.
Alternatively, listening on the <body> level with normal jQuery mechanisms should in general also work.
Which didn't work then I tried using attachPress with the element which obviously didn't exist. Please help.
Does this means that the element on which you are attaching event handler doesn't exists at this point? If this is the case you can hook the handler to some container, upper in the DOM hierarchy which you are sure that exists and filter the click events.
Example:
$("body").on("click", "#myHorizontalLayout", function(){
alert("Hey, you!");
});
As of jQuery 1.7, the .on() method is the preferred method for
attaching event handlers to a document. For earlier versions, the
.bind() method is used for attaching an event handler directly to
elements. Handlers are attached to the currently selected elements in
the jQuery object, so those elements must exist at the point the call
to .bind() occurs.
Reference here
So try replacing bind with on and let me know if it works or not.
I'm currently trying to write what I feel like should be a very simple chrome addon using jquery. I have a tool I use for work that our IT department has stopped supporting Chrome with, because they have enough on their plate troubleshooting IE. Their solution however, was simply to remove the old onClick functions and added the property disabled="diabled" to all of our buttons.
My simple work around for this is using jquery to remove the disabled properly and append the onClick functionality. I've gotten this to work in a few instances, but the problem I'm running into is with new instances of buttons created using ajax forms.
Here's the code I'm currently trying to work with:
function restoreFunctionality() {
$("#RestoreDefaultsButton").removeProp("disabled").attr("onClick", "OnRestoreDeviceClientClick()");
}
RestoreFunctionality();
Now, this works fine for the initial load, however I'd also like this to work for every button that is to be created in the future. To do this, I added:
$("#RestoreDefaultsButton").on("restoreFunctionality", function(event) {
$("#RestoreDefaultsButton").removeProp("disabled").attr("onClick", "OnRestoreDeviceClientClick()");
});
This, however, does not work for me but also does not provide any sort of console error message telling me why it won't work. I can't seem to find an example of what I want. I see examples in the jquery doc where it can be called by clicking somewhere or something like that, however what I want is for it to just simply "work". Just look for new instances of that button ID and make the changes.
Is on() not the function I want to use in jquery 1.11.1? Am I somehow using this incorrectly? Any guidance to point me in the right direction would help.
Edit for clarification:
I am not trying to edit the same button multiple times in multiple locations. I am trying and willing to create code individually for each button that comes up, given I know the ID of each one.
Here is an example of something I have that is currently working:
The line of code for the button reads:
<input type="button" name="RestoreDefaultsButton" value="Submit"
id="RestoreDefaultsButton" disabled="disabled" class="aspNetDisabled InlineButtonStyle">
The code that I am using and that actually works just fine is now:
$("body").on("click", "#RestoreDefaultsButton", restoreDefaultFunctionality());
and restoreDefaultFunctionality() is simply:
$("#RestoreDefaultsButton").removeProp("disabled").attr("onClick", "OnRestoreDeviceClientClick()");
Again, the above code works just fine. What I seem to have trouble with is that not all of my buttons are present on load, I may click a link that loads a model on the same page/url with a form that has additional buttons. That button might read:
<input type="button" name="OpenToolkitButton" value="Submit" id="OpenToolkitButton" disabled="disabled" class="aspNetDisabled InlineButtonStyle">
Which is almost exactly the same as the original example, it's just been loaded after the script ran for the first time.
What I am looking for is a solution to make all individually specified buttons that I need, when they occur, to have that disabled removed and a specific onclick function added.
It appears that you have several things wrong and you are using .on() incorrectly.
First, ids in your document must be unique. You cannot have multiple DOM elements with the same id. That is both illegal HTML and will not correctly work with selectors. So, if you're trying to detect future "#RestoreDefaultsButton" objects in addition to the one you already have, you will have to change that because you can't have more than one and still have selector code work correctly. Usually, you want to use a class name instead of an id when you want to find multiple objects of the same type.
Second, your use of .on() is simply not correct. .on() allows you to register a callback function that will be called when a certain DOM event is triggered. So, when you do this:
$("#RestoreDefaultsButton").on("restoreFunctionality", fn);
You are asking for jQuery to call your function when the single "#RestoreDefaultsButton" object triggers the "restoreFunctionality" DOM event. Since "restoreFunctionality" is not a built-in DOM event, the only way that could ever trigger is if you triggered the event yourself.
The usual solution to modifying newly created objects that are inserted into the DOM is to go find the code that creates those objects and insert a function call (to call your own function that can find and "patch up" the newly created DOM objects right AFTER the newly created DOM objects have been created.
The newest browser versions allow you to register a callback to be notified when certain types of objects are added to the DOM so you could get notified automatically. These notifications are call MutationObservers (doc here). Unfortunately, those events are only implemented in the latest browsers (IE11) so you generally can't solely rely on them for a general web page.
Your click handler assignment could probably be solved with delegated event handling. In delegated event handling for dynamically created objects, you find a persistent object (that is not dynamically created) that will be in the parent chain of your dynamically created element and you bind the click event handler to that parent. Since click events "bubble" up the parent chain, the click event will be seen by the parent. Using the delegated form of .on() that works like this:
$("static parent selector").on("click", "dynamic element selector", fn);
You can then handle the event without worrying about the timing of when the dynamic element is created/destroyed, etc...
You can read more about delegated event handling in these references:
Does jQuery.on() work for elements that are added after the event handler is created?
jQuery .live() vs .on() method for adding a click event after loading dynamic html
jQuery .on does not work but .live does
Are you triggering the "restoreFunctionality" event after your ajax forms are built?
$("#RestoreDefaultsButton").trigger("restoreFunctionality");
Forces it to be synchronous if you have more to do after the call and before you finish the function
$("#RestoreDefaultsButton").triggerHandler("restoreFunctionality");
I am developing a jQuery Mobile and PhoneGap app. I am using this code:
$('#contact').live('pageinit', function() {
//$.mobile.loading('show');
theme();
getData('contact/list',contactList);
//$.mobile.loading('hide');
});
When accessing page for the first time, it works good. In second attempt event is firing multiple times. I tried using bind but it doesn't work.
I think it is connected with live event. It is binded each time I initialize the page, which makes it multiple. Problem is solved when linking that way: window.location.href-it recreates DOM. Unfortunately I can't use it.
Is there any way to handle pageinit in another way?
I tried to find it earlier but with no success. Also looked at: click() firing multiple times
In theory, any event that can be bound by 'live' can be bound directly. The benefit of binding directly is that it will (iirc) overwrite the previous bound handler. As such, you would only have one handler, so it wouldn't get triggered multiple times on subsequent loading.
try something like:
$("#contact").pageInit(function() {
theme();
getData('contact/list', contactList);
});
I usually use the on() method instead of live() (which is now deprecated). I give each of my page containers an id, so on the index page it might be index, then I can bind to the event like:
$(document).on("pageinit", "#index", function() {
//do stuff here
});
Works same way for page show also.
When binding events in jquery mobile, you have to be very cautious as to ensure that they will not be bound multiple times. Navigating to a new page in jquery mobile will not "reset" the bound events as it would in more traditional navigation.
The issue your facing is most probably due to the function being bound to the event every time you access the page, meaning that the more you access the page, the more times you will get that function to be executed when you do.
In order to ensure the event is only bound once, I would recommend binding in the header of your initial page. This way, the event is bound once and for all, and the function will be run whenever this page is initiated.
You can try adding data-ajax="false" to any forms you are submitting that may be creating multiple versions of the page (firing events multiple times).
Consider the following code:
$('div').click(function(){
$(this).animate({height:100}, 500)
$(this).css({opacity:1});
});
Versus:
$('div').click(function(){
$(this).animate({height:100}, 500);
})
.click(function(){
$(this).css({opacity:1});
});
Does jQuery or JavaScript essentially "compile" the second code sample into something like the first rather than maintaining two separate event handlers? I ask about whether jQuery or JavaScript does this because I'd also be interested to know if such "compilation" is a feature of native JS or something implemented by jQuery.
It seems to me that this "compilation" is not actually done, at least not in a way that eliminates the differences between the two code samples. Using JSPerf, I compared the speed between each one and it appears that the first code sample is substantially faster.
Handlers are fired in the order they are bound and each $('div').click() binds another handler to the element in question. In your case the first one only binds 1 event handler and thus performs faster because it only fires one event. The second binds two event handlers, and thus is slower because it fires two events instead of one (more overhead).
I think they are maintained as two separate events. When triggered, they get executed in the same order they were bound.
I'm developing a touchscreen application that, aside from everything else, records the amount of times the screen is used so that the user can be reminded to clean the screen after a predefined number of clicks.
I've got the click functions written nicely, all I need now is make sure the function is called on a click.
I imagine $('*').click(function() { //do something }); would accomplish my goal, but is that the best way? Also, would that overwrite other click functions assigned to the elements?
It would add, not override, but a better solution would be this:
$(document).click(function() {
//do something
});
Since clicks bubble, just listen up at the document level with one event instead of creating events on every element beneath. For the override part...you can add as many handlers as you want, they will just execute in the order they were bound.
The best way is to assign the event handler to document itself. The events bubble and document can catch them all, while still retaining the origin of the event.