In many cases, I need to bind a behaviour to an element after loading, and then after an event triggering (like "change").
I think the best way would be to make it in the same line:
$('#element_id').bind('load, change', function () {
...
});
But this works only for "change" and not for "load". There is a better way?
I stumbled across the same problem. Removing comma is not enough, at least not in this case:
$(document).ready(function(){
$('#element_id').bind('load change', function () {
... // (this DOESN'T get called on page load)
});
});
I guess load events get triggered before $(document).ready().
This is a simple solution:
$(document).ready(function(){
$('#element_id').bind('change', function () {
...
});
$('#element_id').trigger('change');
});
For already loaded content, when you want to run a function on an event and also straight away, you can use a custom event of your own naming to avoid triggering any existing bindings from libraries etc. on the built in events, e.g.
$(".my-selector").on("change rightnow", function() {
// do stuff...
}).triggerHandler("rightnow");
Don't you just need to remove the comma?
try it without the comma:
$('#element_id').bind('load change', function () {
...
});
http://api.jquery.com/bind/#multiple-events
Related
I have the following jQuery on a Rails page:
$(document).on('click','.reportsArrow', function() {
if ( $(this).parent().hasClass('reportCollapsed') ) {
console.log("A");
$(this).parent().removeClass('reportCollapsed');
}else{
$(this).parent().addClass('reportCollapsed');
console.log("B");
}
});
When I click on an element with reportsArrow and without reportCollapsed, the log shows
B
A
Meaning it is executing the else part and then executing the if part. I want the function to only be executed once per click, and to only follow one code path. Why is it being executed twice and how do I stop this? I should point out that this toggles correctly in the mockups created by the web designer (on HTML/CSS/JS only). It looks like the problem is Rails related.
EDIT:
We have found a working solution:
$('.reportsArrow').click(function() {
$(this).parent().toggleClass('reportCollapsed');
});
The event would be getting fired more then once and propagated up-ward in the DOM tree. Use event.stopPropagation(). You can also use the toggleClass instead of branching.
$(document).on('click','.commonClass', function(event) {
event.stopPropagation();
$(this).parent().toggleClass('newClass');
});
Not sure why, but my days in unobtrusive javascript have taught me to be as specific and as least fuzzy as I can.
Never worried why, as long as it worked. Having been asked why (just here), my answer is "I will have to look it up". Sorry.
Thus, I would avoid setting a catch method on THE document and then filter actions: I would directly point the event catches on the element (or set of elements) I want to watch.
So, instead of using:
$(document).on('click','.reportsArrow', function() {
//...
});
I would go the direct way:
$('.reportsArrow').click(function () {
//..
});
Having read the API documentation for jQuery .on(), it appears to me that it would be probably more suitable to use .one() instead, so there is no continuation after hit "#1". But I have not tested it, so I can't say for sure.
You need to stop event propogation to child elements.also you can use toggleClass instead:
$(document).on('click','.commonClass', function(e) {
e.stopPropagation();
$(this).parent().toggleClass('newClass')
});
Try this,
You need to avoid event bubbling up the DOM tree. There must be a parent causing the event to fire twice or more time.
To avoid this use event.stopPropagation()
$(document).on('click','.commonClass', function(event) {
event.stopPropagation();
$(this).parent().toggleClass('newClass');
});
I could not reproduce your problem. Your code is working fine in my Firefox on a simple HTML page.
Please try this piece of code and come back with the console output:
function onClick(ev) {
console.log(ev.currentTarget, '\n', ev.target, '\n', ev);
if(ev.target === ev.currentTarget)
console.log($(this).parent().toggleClass('newClass').hasClass('newClass') ? 'B' : 'A');
};
EDIT:
and of course:
$(document).on('click', '.commonClass', onClick);
For readability put the logic into the jQuery selector using the :not like this
$(document).on('click','.reportCollapsed > .reportsArrow', function() {
$(this).parent().removeClass('reportCollapsed')
console.log("A");
})
$(document).on('click','not:(.reportCollapsed) > .reportsArrow', function() {
$(this).parent().addClass('reportCollapsed')
console.log("B");
})
Given that this works one time (click > else > B) could it be that something listens for DOMSubtreeModified or other DOMChange Events which again trigger a click on the document ?
Have you tried debugging/following the calls after the inital click? Afaik chrome has a nice gui to do this.
I'm using infinite-scroll, a plugin that replaces the standard pagination by fetching new pages through ajax.
The problem with this is that jquery functions don't register the new posts, causing functions like these:
jQuery(document).ready(function($) {
$('.vote-a, .vote-b').click(function() {
//do stuff
});
$('.vote-b').click(function() {
//do other stuff
});
});
to stop running. To solve this, the plugin provides callback, and let's you include codes that you'd like to be called whenever a new page is loaded.
What I did was simply putting the code above there. It worked but I ended up with several instances of the same code.
So the question is how do I solve this? One way I can think of is destroying/removing the old instance with each callback.
Or somehow reinitiliaze/restart/invoke the function.
You can register the click events at a root level instead of by finding the individual elements and assigning a click event to them.
https://api.jquery.com/on/
and the older method
https://api.jquery.com/live/
jQuery(document).ready(function($) {
$(document).on('click', '.vote-a, .vote-b', function() {
//do stuff
});
$(document).on('click', '.vote-b', function() {
//do other stuff
});
});
In JS / jQuery there's often a need to do something and then repeat it under certain circumstances.
For example something like this, it's only an example:
$(window).load(function() {
scaleSomething();
$(window).resize(function() {
scaleSomething();
});
});
What would be the elegant way to write something like this? Because in such situations one function / block of code is always doubled.
You have to use .on to bind multiple events. Please read here to know more about it.
Try,
$(window).on('load resize',scaleSomething)
You can group space-separated events when using ".on" method:
$(window).on("load resize", function() {
scaleSomething();
});
http://api.jquery.com/on/
Try to trigger the event immediately after you create a listener:
$(window).on('resize', function() {
scaleSomething()
}).trigger('resize');
Use on to attach an event handler to multiple events. The events are passed as the first argument to the on function. The argument should be a string with event names delimited by spaces.
$(window).on("load resize", function(){
scaleSomething();
});
function scaleSomething(){
alert("scaling");
}
JS Fiddle: http://jsfiddle.net/7ZFpr/
I would like to call function when slideUp or slideDown are performed on an element. Is this possible?
Something like:
$('#panel').on('slideUp', function() { open--; });
$('#panel').on('slideDown', function() { open++; });
Update: The problem is that there are a ton of slide calls (e.g.: $().slideUp()) all over the page, within ajax responses, hash link clicks, etc.. I was hoping to bind to the slide itself somehow rather than add code to each calling function.
You cannot bind to an event since there is no such.
But you can pass a handler that will be called after animation is finished
$('#panel').slideUp(function() { ... });
http://api.jquery.com/slideUp/
If you really want to do this, you can use custom events and your own little plugin, something like this:
$.fn.mySlideToggle = function() {
this.slideToggle();
this.trigger('mySlideToggle');
}
$('div').on('mySlideToggle', function(){ console.log('hey') });
$('button').on('click', function(){ $('div').mySlideToggle(); });
Here's a little demo (check console): http://jsbin.com/asejif/2/edit
In your case it is redundant though, since you can use the callback that the slide events provide, but it might be useful for other things...
I think I've been too much time looking at this function and just got stuck trying to figure out the nice clean way to do it.
It's a jQuery function that adds a click event to any div that has a click CSS class. When that div.click is clicked it redirects the user to the first link found in it.
function clickabledivs() {
$('.click').each(
function (intIndex) {
$(this).bind("click", function(){
window.location = $( "#"+$(this).attr('id')+" a:first-child" ).attr('href');
});
}
);
}
The code simply works although I'm pretty sure there is a fairly better way to accomplish it, specially the selector I am using: $( "#"+$(this).attr('id')+" a:first-child" ). Everything looks long and slow. Any ideas?
Please let me know if you need more details.
PS: I've found some really nice jQuery benchmarking reference from Project2k.de here:
http://blog.projekt2k.de/2010/01/benchmarking-jquery-1-4/
Depending on how many of these div.click elements you have, you may want to use event delegation to handle these clicks. This means using a single event handler for all divs that have the click class. Then, inside that event handler, your callback acts based on which div.click the event originated from. Like this:
$('#div-click-parent').click(function (event)
{
var $target = $(event.target); // the element that fired the original click event
if ($target.is('div.click'))
{
window.location.href = $target.find('a').attr('href');
}
});
Fewer event handlers means better scaling - more div.click elements won't slow down your event handling.
optimized delegation with jQuery 1.7+
$('#div-click-parent').on('click', 'div.click', function () {
window.location.href = $(this).find('a').attr('href');
});
Instead of binding all the clicks on load, why not bind them on click? Should be much more optimal.
$(document).ready(function() {
$('.click').click(function() {
window.location = $(this).children('a:first').attr('href');
return false;
});
});
I would probably do something like;
$('.click').click(function(e){
window.location.href = $(this).find('a').attr('href');
});