Execute JS function each time element with specified selector is added - javascript

I got to refactor big one-page application with complex UI.
There is following code in document.ready function
$('table.datatable').dataTable({ ... params ... });
$('div.tooltip').tooltip({ ... params ... });
$('ul.dropdownMenu').menu({ ... params ... });
As you can see in this code we search for different HTML controls and call to appropriate jQuery plugins that implement these controls' behavior.
However, since the page is very dynamic new datatables, tooltips and menus are added all the time and since JS functions were called at very beginning of application - those elements have no needed functionality unless I manually call appropriate plugin for them.
I'd like to eliminate the need to call jQuery plugin after each DOM change but don't know how to do it better.
One option is to fire an event each time I am adding anything to DOM and re-call this plugins in event's listener, however I don't like this solution because of need to remember fire the event each time.
I read about jQuery's on function which attach events also for not yet exists elements, but what event do I need? AFAIK there is no domchange event.
Any advises?

Your only option is to hook up your plug-ins on new items after they are added to the DOM. The best cross browser option would be to hook into each place that adds these types of elements to the DOM and simply deal with the new items there by calling some additional function on them. What you need to look for is where you can easily hook into your existing code after new elements have been added to the DOM and then fix up those new elements at that point. Without knowing your code and where the DOM is modified, we can't really advise the best way to do that.
Generically monitoring the DOM for new items with a single method is not possible in a cross browser fashion. Mutation observers are the latest standard way to do this, but it is not supported in many browsers yet. Mutation events came before mutation observers, but is now deprecated.
jQuery's .on() will not do what you want here - it can be used to handle dynamically added DOM elements, but not in the way you want. Your plug-ins could have been designed to handle their events with use .on(), but unless they were designed that way and you can take advantage of that, there isn't a simple way for you to use it to get your desired behavior without rewriting a portion of the plugin.

Related

What's the smartest way to refresh dom handlers after new ajax-loaded content?

I'm working with a large template of charts and other widgets. I also manually implemented some ajax tabs. Now whenever those tabs load new content (charts), the problem is that all the template scripts in the head tag won't work with those ajax-loaded elements anymore.
I know, normally you would use .live for this kind of problem, but this would mean to go into the whole 50k lines-js template and change everything to .live calls... Not really able to do that.
Is there instead a jquery way of reloading/reactivating all the scripts within the head-tag?
First off .live() has long since been deprecated and even removed from the latest versions of jQuery. You should never be thinking of using .live().
Second, as it sounds like you already know, the "right" way to fix this is to change your code to use the delegated form of .on() which is what replaced .live(). Yes, change all the code that does it the wrong way. Here's a post on using the delegated form of .on() instead of .live().
Third, a work-around would be to put all your initialization code that hooks up these event handlers into a single function (or called by a single function). Then, you call that single function upon initialization and then you can call that single function any time later after you reload your content. The trick is that you can only put code into that initialization function that can be called or should be called more than once after you content has been reloaded. If you put some event handlers in there that should not be in there, then you may get duplicate event handlers installed. So, only event handler initialization that applies to the replaced content should go in this function.
Suppose that function was called initDynamicContent, then it could look like this:
// init event handlers on the original version of the dynamic content
$(document).ready(initDynamicContent);
Then, sometime later after you replace the dynamic content, you can just do:
// code here that replaces the dynamic content with new content
initDynamicContent();
There is no magic jQuery way for this to happen automatically. jQuery has absolutely no way of knowing which code should be run again and which code should not.

How does JQuery create it's Custom Events and can I recreate in Javascript?

I am looking to create events in Javascript using the same methodology as JQuery- Does anyone know how JQuery does it?
My reasoning is that using raw Javascript such this:
var myEvent = new CustomEvent("userLogin", eventProperties);
...does not actually work on Android native browser, as it does not support DOM Level 3 like Chrome and other browsers do.
However, JQuery does work on Android's stock browser, and simply uses:
$.event.trigger('MyEvent');
My question is, what is the code behind this? I tried to find it by going through JQuery's source code, but cannot get my head around it!
The fundamental thing here is this: When you hook an event handler up with jQuery, jQuery doesn't directly add that handler to the DOM element. Instead, jQuery hooks up a handler of its own on the DOM element (if it doesn't already have one on it). When the event occurs, jQuery looks at the list of jQuery-registered handlers for the event and fires them in order. (There are several reasons for this; initially it was primarily around IE memory leaks and the fact that IE fired handlers in one order, and everyone else in a different order; so jQuery took over and ensured the order.)
(You might be able to see where I'm going with this...)
So when you use trigger, jQuery sends the synthetic event to the DOM element, but it doesn't rely on that synthetic event to work; it calls the handlers you've registered through jQuery directly. In fact, it sets a flag so that it knows that it's done that, so if the browser does send the event to jQuery's handler for it, jQuery knows to ignore it (since it's already done its work).
You can see this in all its glory starting with line 4,464 of the current uncompressed jQuery file.
So basically jQuery's build its own pub/sub system, and only uses the browser event system as an input to it. So custom events don't usually have to talk to the browser at all.

effects of javascript not work in ajax reply

I am new in AJAX. I have searched a lot on Internet but only got basic AJAX steps. Now I am writing codes using AJAX but a common problem I am facing continuously.
When I place return text in the particular id of HTML page, Javascript effects do not work. CSS works fine but Javascript effects like table sorting, jQuery effects or any other effect does not work. I know I am missing some concept here. But didn't get any effective answer.
Please suggest me what should I do? And what is the concept behind this...
The new HTML you're adding to the DOM (page) didn't exist when your jquery ran the first time and bound events to elements on the page. You're probably using $("something").click(...) or .bind("click", ...). Instead of these use the delegate function from jquery. Delegate is generally more flexible and faster than live. For instance you can not stopPropagation in a 'live' binding.
Jquery Delegate
Why Delegate is better than Live
Here is another SO answer that explains the benefits of delegate
What's most likely happening is that your events are getting unbound because you update the DOM with new elements. The easiest solution is to use the live method to bind to events : http://api.jquery.com/live/
Or you can simply rebind the events to the elements after insertion to the DOM just as easily.
EDIT
As user kasdega points out, another alternative is to use delegate : http://api.jquery.com/delegate/ Delegate works by using the bound root elements as the context to rebind events to DOM elements that may appear in the future.

How can I force the DOM to re-eval in Javascript/jQuery?

I am dynamically appending HTML to a webpage and I'm also using jQuery to manage stuff.
When I add HTML code, jQuery ignores its existence.
For example:
$("td.elementToClick").click(...
Will work great with jQuery. But if somewhere in the code I append:
$("tr#myRowToAppend").append("<td class="elementToClick>...</td>");
jQuery will ignore this new element if I click on it.
As jQuery associates the events after the page finishes loading, I need one of two solutions:
- Force the DOM to re eval the page without changing the current layout (I don't wish a refresh, so location.reload() is out of the question).
- Force jQuery to add this new element to it's internal event manager.
I don't wish to use onclick="blabla()", I really need to use jQuery.
How can I accomplish this?
What you are looking for is jQuery live. From docs description: "Binds a handler to an event (like click) for all current - and future - matched element. Can also bind custom events."
There is also a plugin liveQuery that supports a wider range of events if you want.
the live() method will alleviate most of your headaches.
I see this happening more often in IE and with cloned elements, to support IE you have to be much more careful with DOM manipulation.
I also see alot of questions on SO with people having issues of copying/moving dom elements to new parts of the dom without cloning it first, which doesn't workout so well in IE.
So you can use live or when you have to handle events from dynamically inserted DOM elements, make sure you clone them with clone(true) to specify you want the events copied:
$("body").append('<div id="one"></div>");
$("#one").mouseover(function(){});
$("body").append( $("#one").clone(true).attr('id','two') );

Trying to wrap my head around custom events

I'm trying to get my head around custom events. I understand how to register and trigger custom events. However, it seems like its not possible to register truly custom events. Everything has to trace back to a DOM event like click, onload, blur, etc. Or am I wrong?
For example, suppose I have an array. I want to register an event that fires when the length of the array changes. To my understanding, I would have to register the event and then create a setInterval timer that checks the current array length against the previously stored length. If the length has changed, I would then need to trigger my custom event from inside the setInterval.
Is there a way to register an event for my array and have it fire automatically when the length changes?
Custom events are in the W3C spec, but none of the major browsers support them. This is why several other users have suggested 3rd party libraries. Prototype, YUI, JQuery, and most others have these capabilities. You can also roll your own.
If you'd like to see what some custom event syntax might look like, you can take a look at this tutorial for Prototype custom events. Some important points:
Prototype custom events must be attached to DOM elements, so that they can bubble like native events.
They must be in a prefix:event syntax in order to fire
They can contain a highly-useful memo parameter that allows any arbitrary context or set of objects to bubble with the event.
why don't you write a method addElement for your array that you'll use whenever you want to insert elements,that way you will be able to write code in the event of array.length change.
same thing with removeElement.
Events are not meant to be used for this kind of thing.

Categories