jQuery: Use live event to add tabindex attributes - javascript

Would like all new elements with class .link to have a tabindex.
Delegate/Live does not seem to work:
$('body').delegate('.link', 'load', function(event){
$(this).attr('tabindex',0);
});
Trying to apply this to AJAX loaded elements. And using what I found in this answer, which suggests the "load" event may be possible.
I'd like to avoid using trigger, or modifying the AJAX callback.

The problem here is that no events are triggered when a new element is inserted into the DOM1. The "solution" (not the one you're looking for, unfortunately) is to set the tabindex from the complete callbacks of your ajax operations. You may use .ajaxComplete() to setup a global/default callback, but that may introduce new problems (such as having to deal with the order events are fired).
Well, that's not 100% accurate; there are the Mutation Events, which are not implemented consistently across different browsers, and are supposed to be replaced by Mutation Observers.

Related

Alternative to Falsely Triggering an Event

TLDR Below
JS Fiddle To Demo
I've been really involved in recreating the tools that are foundations of premiere JS Libraries to better improve my skills. Currently I'm working on functional data-binding a la Angular.
The idea of data-binding is to take data and bind it to elements so that if manipulated all elements subscribed will change accordingly. I've gotten it to work but one thing I hadn't considered going into it was the issue with innerHTML vs value. Depending on the element you need to change one or the other( in the demo above you'll see that I needed to specifically single out the button element in a conditional statement because it has both, but that's kind of a fringe case )
The issue is that in order to capture a SPAN tag update I needed to trigger an event to happen, and the easiest one to manipulate for Text Boxes/Textareas was 'keyup'.
In my function then, if you pass in an element with no value property we assume you're going to be updating innerHTML, and we setup an observer to determine if the element ever mutates, and if it ever does, the observer will emit a 'keyup' event.
if (watchee.value == void(0)) {
var keyUpEvent = new Event('keyup');
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
watchee.dispatchEvent(keyUpEvent);
});
});
observer.observe(watchee, {
childList: true
});
}
Now it may just be my paranoia, but it seems like I might be tunneling into a can of worms by faking 'keyup' on an element that doesn't natively have that support.
TLDR:
I'm curious if there's an alternative way to make, a.e. a span tag reactive other than faking a 'keyup'/'keydown'/'change' event? For instance, is there a way that I can make my own pure event(by pure I mean not reliant on other events) that checks if innerHTML or value has changed and then performs a function? I know that this is probably possible with a timer, but I feel like that might hinder performance.
EDIT: just an aside. In the demo the function called hookFrom works by taking a DOM node and returning a function that will take the receiving dom node and continues to return a function that will take additional receiving dom nodes. :
hookFrom(sender)(receiver);
hookFrom(sender)(receiver)(receiver2);
hookFrom(sender)(receiver)(receiver2)(receiver3)(receiver4)...(receiver999)...etc
JS Fiddle To Demo (same as above)
There is nothing inherently wrong with creating a similar event on a DOM node that doesn't natively have that functionality. In fact this happens in a lot of cases when trying to polyfill functionality for separate browsers and platforms.
The only issue with doing this sort of DOM magic is that it can cause redundancy in other events. For instance the example given in this article: https://davidwalsh.name/dont-trigger-real-event-names shows how a newly minted event using the same event name can cause problems.
The advice is useful, but negligible in this specific case. The code adds the same functionality between text boxes, divs, spans, etc... and they are all intentionally handled the same way, and if the event would bubble up to another event, it would be intentional and planned.
In short: There is a can of worms that one can tunnel into while faking already explicitly defined event names, but in this case, the code is fine!

Unbind events on elements that will be added to DOM later

I have a div with class="backdrop". This will be added to DOM when I click a button. To this is bound an event of 'wheel'.
I cannot avoid the binding of the event(happening through library) So i will want to unbind this globally.
I tried : $(".modal-backdrop.am-fade").unbind('wheel');
This works but I have to write this statement after each time the div is added to the DOM. I want something which I can write only once and would apply to all the divs which would be added to the DOM in future
I want something which I can write only once and would apply to all the divs which would be added to the DOM in future
If code in the library you're using is adding elements and binding events to them, you'll have to unbind them as you go, there's no alternative.
If you already have some way of triggering that (the library tells you when it adds a div), then you'll just have to have that code respond to that event.
If you don't already have some way of triggering it, you can use mutation observers to watch for the divs being added so you can unbind them. They're well-supported by modern browsers. Slightly less modern browsers may have sufficient support for the old mutation events that you can use a library that provides a mutation observer polyfill using mutation events (just search for "mutation observer polyfill"). Worst case, on really old browsers, you'll have to poll.
Of course, the best answer is to either stop using the library if it doesn't do what you want, or modify it (this is JavaScript, after all) so it doesn't do what you don't want.

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

Possible to monitor when an image is being added/removed from a div?

If it's possible to somehow monitor a change in a div's DOM then that would be my solution - that will be enough to fire my event handler, but in case that's not possible - this is my problem:
I have a div, some javascript function (out of my control) will add or remove an image to this div (potentially nested in several divs/spans).
I need to attach an event (if possible using jQuery) that will fire when this particular image is added or not.
EDIT: To clarify - when I say added - I don't mean some sort of toggle of it's display attribute, I mean literally completely added or completely removed.
You can use the mutation events for that purpose. Be aware that some of those events are deprecated by now.
$('div').on( 'DOMSubtreeModified', function( event ) {
// something was changed
});
If you just need to know if some node was added, use
$('div').on( 'DOMNodeInserted', function( event ) {
// something was changed
});
The event object will give you further information about what exactly happend.
Since you asked for an alternative, there is the jQuery livequery plugin. AFAIK, i'll also use the Mutation Events if available, but it claims to be compatible with all browsers jQuery supports. That means, they will use a fallback solution (most likely intervall timers) to check for changes in incompatible browsers.
Further read: Mutation Events

Circumvent the DOMNodeInsertedIntoDocument event

Assume I have a javascript function createMyElement which returns a node that can be inserted into an HTML document.
In order to function properly, the code of the node created by createMyElement has to listen for events on the global document at least as soon as it is inserted in the document.
My first attempt was to add DOMNodeInsertedIntoDocument and DOMNodeRemovedFromDocument listeners to the node at creation time that add and remove the needed listener on document in turn.
However, the mutation events are deprecated by now (and don't seem to work reliably across browsers), so I am looking for a better solution.
Adding the listener for events at document at the creation time of the node would work. However, this doesn't seem to be a good solution as it would create memory and performance leaks: Even after the node was being removed from the document again and not needed anymore, the listener (and its references to the node) on the document would still persist.
Use a series of function callbacks or on-demand script callbacks to serialize the events.
Since I originally asked my question, the substitute for mutation events, namely mutation observers as defined in http://www.w3.org/TR/domcore/#mutation-observers, have been implemented in a number of browsers.
So a simple answer to my own question is to simply use mutation observers on the document to listen for nodes to be inserted or removed.
An even better way, however, is to use the new custom elements from https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html, which gives one insertedCallbacks and removedCallbacks for custom elements.

Categories

Resources