JavaScript Function on Injected Content - javascript

So something I'm curious about, how the YUI3 PJAX works. For instance, when used, even if you inject an anchor into the page with the yui3-pjax class and click it - that will run the AJAX function.
My question is does that use a Promise or what to determine if the anchor, including injected anchors, has the class?
I have a function for observing mutations for a site and I call it on the click event for the yui3-pjax anchors already existing in the page, but I also want to have it run on yui3-pjax anchors that I dynamically load into the page without having to recall the function.

Using jQuery for the ease of sample code, a similar solution can be written in vanilla Javascript as well.
You can use .on() with a selector parameter. For example:
$('body').on('click', '.class', function(e) {
e.stopPropagation(); //Stop multiple possible triggers from the same click
//TODO: Rest of code
});
The downside obviously being that every click on your highest common ancestor will get processed. The upside is however that since the click is caught there (not on the elements themselves) you don't have to worry about rebinding events.

Related

jQuery selectors not working after ASP.NET postback (no UpdatePanels, not AJAX)

I need to make a change to an old page as quickly as possible, and the effort to AJAX-ify it in order to obviate postbacks would take too long (making a more correct version of it will have to come later, this new functionality needs to be in place ASAP). The javscript changes required are too complicated to attempt entirely in the plain JS the page currently uses for everything (it's enough of a mess as is), so I decided to implement the new functionality quickly using jQuery.
Everything works fine until there's a postback, after which the document ready function still runs, but the selectors no longer find anything. I'm not using ASP.NET AJAX, so there's no UpdatePanels or partial postbacks.
What's happening and how can I fix it in the simplest, fastest possible way?
While $(document).ready() is ideal for one-time initialization routines, it leaves you hanging if you have code that needs to be re-run after every partial postback. Of course there are ways to get around this. But can you try using .NET franeworks pageLoad() and bind your events there and see if selectors still work after postback.
<script type="text/javascript">
function pageLoad() {
$("#Button1").on('click', function () {
...
});
}
</script>
If you have a a trigger attached to the DOM, and that element in the DOM gets replaced, the trigger will be lost. Such a trigger might look like $('#mydiv').on('click', function(){});.
Instead, you have the attach the trigger to a DOM element that wont be replaced. The easy way is to attach this to the document, but you'd be recommended to narrow the search.
Such a selector would look like
$('document').on('click', '#mydiv', function() {});
This means that if the element #mydiv gets recreated, then the trigger is not lost.
You can read more about delegated events at http://api.jquery.com/on/

Can't modify properties of element using jquery .on()

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

javascript / jquery performance

What happens in jQuery with .on() event if its element doesn't exist in the DOM?
For example, if I use this:
$(document).on('click', "#registerFormSubmit", function(){
// do something here
});
And I don't have #registerFormSubmit present on all pages, is the browser slowed down by the code, or is it not?
So why am I doing this anyway?
I don't want to split my javascript code to 10 .js files and include each depending on which is required on which page, as I believe the server/browser will transmit the data a lot faster if it's in 1 file (especially if the file is obfuscated and minified).
If the code slows down even pages not containing the element, would the following be a good solution to keep all the code in one file?
var page = window.location.pathname.split('/');
if (page[1] == 'contact'){
$(document).on('click', "#registerFormSubmit", function(){
// do something here
});
}
Remember that the .on() event attaches an event handler function for whatever element is in the DOM or will be in the DOM in the future. Therefore I believe it would slow the browser down even if the element isn't present at the moment.
However, the proposed if (page) solution should not attach the event if the page isn't matched, imo.
Can anyone shed some light on this, please?
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.
jQuery can process simple selectors of the form tag#id.class very quickly when they are used to filter delegated events. So, "#myForm", "a.external", and "button" are all fast selectors. Delegated events that use more complex selectors, particularly hierarchical ones, can be several times slower--although they are still fast enough for most applications. Hierarchical selectors can often be avoided simply by attaching the handler to a more appropriate point in the document. For example, instead of $("body").on("click", "#commentForm .addNew", addComment) use $("#commentForm").on("click", ".addNew", addComment).
source: http://api.jquery.com/on/
I will suggest you to use above mentioned format instead of $(document).on('click', "#registerFormSubmit") and if you are not going to use the click event in all pages then simple answer is don't put it in all .js files. Load only the required .js files and handle registerFormSubmit click event in separate .js file.

Loading HTML using JQuery's getScript multiple times after the HTML is removed over and over

I have a SPA ( single page application ) programmed in HTML/JavaScript/JQuery/CSS
Every time a navigation link is clicked the main div is loaded with a chunk of HTML/JavaScript/JQuery/CSS via the ajax command and the getScript function is used to load the JavaScript/JQuery portion of that chunk.
Once a user clicks on another link, the main div is removed via the remove() function and the new chunk with its JavaScript/Jquery replaces it.
HERE'S THE PROBLEM: when I load the content of the main div for the second, third, etc. time ( if a user clicks on another link but then comes back to this one ) do I run the getScript function again to load the JavaScript/JQuery? If so - wouldn't it bind the "on" and other events over each other, or does the remove() function take care of it and it's safe to do without any memory leak?
Thank you for your responses!
From http://api.jquery.com/remove/
Similar to .empty(), the .remove() method takes elements out of the DOM. Use .remove() when you want to remove the element itself, as well as everything inside it. In addition to the elements themselves, all bound events and jQuery data associated with the elements are removed. To remove the elements without removing data and events, use .detach() instead.
So all events bound on the div and its descendants will be removed and can be safely rebound. However if the JavaScript you are injecting binds events to things outside the div like the document, window, body etc.. multiple events will be bound which will likely cause problems if unintended.
As of jQuery 1.4, the same event handler can be bound to an element multiple times. This is especially useful when the event.data feature is being used, or when other unique data resides in a closure around the event handler function.
http://api.jquery.com/on/
If you absolutely must bind to higher level elements from the script that is run repeatedly then you should look in to using off() before you bind the events.

How to find what ASP.NET AJAX event handlers are associated with a DOM element?

I'm customizing an existing ASP.NET 3.5 AJAX web application that I can't modify the source code to (it's SharePoint 2010).
I need to add a click event handler as the first event on a Close button. However, I'd like to check what the existing event handlers already registered on this button do first, so I don't mess anything up.
I'm still learning ASP.NET AJAX and can see the Sys.UI.DomEvent class has methods to add and remove event handlers, but not enumerate them. I know jQuery and am familiar with JavaScript debugging in Chrome.
How can I see which events are registered and insert a custom event handler at a particular position?
There is a technique that will at least allow you to be the first in line (unless another script employs the same trick - unlikely).
What you have to do is hijack the click event. This related question demonstrates the technique: Hijacking onchange event without interfering with original function
All we do is redefine the click function to be one of our own choosing, e.g.
var myButton = document.getElementById('button1')
var oldClick = myButton.click;
myButton.click = function(evt) {
//do whatever you want. When done, call the default click function:
if (oldClick) oldClick(evt);
}
(the syntax in the linked question is superior, but the above code is easier to read).

Categories

Resources