Understanding JavaScript events and applying jQuery events/plugins? - javascript

I have a bunch of jQuery functions that use the .on event because I want to prevent reapplying the event to the same element.
However some people created plugins (e.g. Owl Carousel) and I don't know how to prevent this event from reapplying.
Currently I am using the plugin as following:
HTML:
<div class="init-owl"></div>
JS:
$('.init-owl').owlCarrousel();
$('.init-owl').removeClass('init-owl');
Whenever a second element gets loaded in the page using e.g. AJAX, I want to only apply the event to the newly added element.
Question: What I dont understand is how the event stays stuck to the DOM?
To better grip what is happening, I was wondering how an event in general gets connected to the DOM?
Is there a better way to prevent events applying to the same DOM elements?
If I wish to write my own plugins, I would need to know how javascript works, right?

Question: What I dont understand is how the event stays stuck to the DOM?
Once an event is bound to an object, it gets removed when the object gets garbaged collected. So if a DOM element is really gone and there are no references to it, then the event will get swept up as well.
To better grip what is happening, I was wondering how an event in general gets connected to the DOM?
I'm not sure how far you want to dive into this. Maybe it would help if you stop thinking about the DOM and events and look more at just regular events bound to objects. Basically an object does something, or something is done to it and some underlying code (in the browser's code in this case) triggers an event on that object. The implementations between browsers may differ, but basically you will have a key or string (the event name) that maps to a collection of functions. When you add an event listener, you add another function to this collection. Then when something triggers that event, it iterates through the functions and executes them. That's a real basic explanation, but I hope it makes things a little more clear.
Is there a better way to prevent events applying to the same DOM elements?
Make sure you don't add the events again by writing better code. I don't believe you can dive down into an element and look to see if it has events bound to it. You can however change your jQuery selector to only target newly added elements. If you have to, mark the elements that you have added events to with a class or something. Then you could target your elements by doing $('.init-owl:not(.already-bound)'). There is a better solution to your problem, I can assure you, but we might need more context and code to see a better way to help you.
EDIT:
You can look into jQuery's off() function to remove events. That may help you too.

Related

How to know what JavaScript functions are bound to an HTML element?

I want to know what JavaScript function is allocated to the events of an HTML element, an input, for example. I would like to check if it has any function bound to the onmouseover, or onclick, or any other event.
In plain JavaScript, that information is not accessible.
So, your options:
Some frameworks like you track event listeners provided you used their syntax to bind them (like jQuery).
Some libraries will "rewrite" how event tracking works (like VisualEvent)
Lastly, you can write your own wrapper around the add/removeEventListener functions, so that it tracks that information in addition to calling the native add/removeEventListener functions. Making sure it wraps all the possible ones, though, can be a challenge.
Inspect your input box in Google Chrome browser, you can check the Event Listeners tab. You can also make use of timeline to track the firing events and effectively use DOM break points.

Binding to dynamic elements

I have some dynamic content that I am loading in via jQuery .load(). I have been trying to utilize the .on method, since the .live method is deprecated to bind elements to the page before they actually exist. I was able to achieve that but in this particular case the method I am invoking is firing twice. Any ideas and or solutions would be greatly appreciated.
I have tried unbinding('click') before binding and that seem to work but it causes the item I am trying to click on to fire on the second click. I also tried event.stopPropagation with no luck. Below is the code I currently have in place. I am currently utilizing the setTimeout approach until I can find a suitable solution.
$('#content').unbind('click').on('click', '.alternate-options', function(event){
//setTimeout(function(){
$('.alternate-option').each(function (index) {
$(this).bind('click', function (event) {
event.preventDefault();
$('.alternate-options li').each(function () {
$(this).removeClass('current');
});
$(this).addClass('current');
});
});
//},100);
});
Joel's answer is correct, but I thought it would be useful to explain it a little bit for others that might come across this in the future.
The deprecation of live() caused a lot of confusion for folks, but the replacement recommended technique really is a lot better once you understand it well.
First, the basics. If you're dynamically adding DOM elements to the page, you have to choose an approach to handling events on them.
One approach is to manually add event handlers to each element as they are dynamically added, typically you'd either add a data-* attribute to indicate the unique attribute of the dynamically added element, or you'd stick an object onto the DOM element itself that can be later retrieved in the event.
The old jquery approach let you simplify this process by using the live() API. In this case, you'd have a selector, and the DOM would be monitored for changes to that selector. This was pretty simple from the developer's perspective but had some major drawbacks. For more information this SO post describes some of the issues well: What's wrong with the jQuery live method?
The newer, and better approach is to use the on() method and look at a parent container DOM element, with an optional selector as a filter.
The reason why this works well is because it uses the normal DOM event bubbling behavior. When you trigger a bubbleable event (like click) on an element, that event will naturally "bubble" up the DOM, with a chance to catch it on each parent element all the way up the scene graph.
In the case of dynamic elements, this works really well. If you have a div, for example, that you're listening for a click event on, that event will be caught for any click events that were triggered by children, no mater when they were added to the DOM.
It would be a little annoying, however, to have to do a bunch of "if" statements inside of that click handler to determine if the element that was clicked was the one you're interested in. This is why the smart folks on the jquery team added the optional filter argument to the on() function. It let's you filter out events that were triggered by elements you don't care about.
This is why Joel's simple example works: you don't need to worry about directly adding event listeners to child elements or anything like that, you are just listening to the events on the container and filtering on the specific elements you care about.
This should do what you want it to:
$("#content").on("click", ".alternate-option li", function () {
$(".alternate-option li.current").removeClass("current");
$(this).addClass("current");
});
No need to rebind events or anything.
Here's a fiddle illustrating this binding with the dynamic content (both adding new list item or completely replacing the entire list):
http://jsfiddle.net/2jKCL/

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.

Javascript performance ? - Put events in html tag, or bind them?

I'm wondering which is better for performance... I have a "web app" sort of thing. It has a lot of javascript. When a button is clicked, a hidden div becomes visible. This new div has 5 buttons. Which is better for performance:
1.) put the button click events in the html tag of each button like onClick="alert('hey');"
2.) Attach events to each button when the div is visible, and then remove the events when I hide the div containing the buttons?
The reason I ask is because I imagine the page might get bogged down if the events in the html tags are constantly there. I figure the page might be faster to only have those events when the user can see the buttons to click them.
Any help is great! Thanks!
I would use event delegation.
This way you can freely add/remove any buttons without worrying about attaching events on each one of them. This approach is also more memory efficient, since you always have one single event handler instead of N ones directly on each button.
Unless those events are causing something to act as a link (which it seems Google learned to read) the put all this JS outside your HTML. It makes your code tidier and more maintainable.
Can't be sure about performance.
Keeping the event handlers registered when the elements are hidden will have no impact on performance, since the events won't fire.
Whether to use HTML attributes or the DOM to register event handlers isn't a matter of performance, it's a matter of clean design. You'll want to keep presentation as separate from behavior as possible. This means that if you use attributes, they should only bind the event to a handler (i.e. call a single function) rather than contain more complex code. That is, don't:
<button onclick="if ('red'==this.parent.style.backgroundColor) {...}">...</button>
do:
<button onclick="clickColorButton(event)">...</button>

which HTML element lost focus?

in javascript, when I receive a focus event, how can I work out which element has lost focus? I'm trying to avoid having to put an onblur event handler on all elements within my web page.
#pbrodka: the target/srcElement property would refer to the element with focus for onfocus events
offhand I can't see a way to get this short of onblur, or if the set of objects you care about all have focus methods you could store a reference to that object instead. It's also possible event bubbling could get you out of jail
this all feels like a bit of a code smell though - perhaps you need to describe the problem in more detail
Difficult this. You cannot use event delegation to find out which control last produced a blur as focus/blur do not bubble up. There have been some attempts to 'fix' this but they are buggy and not resiliant cross browser.
Could I ask you why do you need this information as maybe there is an alternative solution.
Unfortunately, the onblur event doesn't bubble, otherwise you could have handled it at the window level to always know when an element lost focus.
As things are, I do believe it will be hard to do without, as you say, adding an onblur event handler to all elements (a truly nasty solution ;-).
It is possible to delegate the focus and blur events, if you follow PPK's advice, here:
http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
The most simple solution is to write a function that walks all forms and then all elements within the form and installs an onblur handler for each (which will probably call some global function). This handler will get an event and this event will contain the info you seek.
This way, you just have to call this method once in body.onload and it will work no matter how complex your document is.
The only drawback is that you will need to call it if you dynamically add forms to your current document. In this case, you must make sure not to install the handler again (or you will get spurious duplicate events).

Categories