jQuery animation and live event - javascript

I load a page with AJAX. That page contains the following code (for div' movement animation, #1 moves it to the left and #2 moves it back again)
#1
$('#flipper').click(function () {
$(".l-l").animate({ "left": -267 }, 600, function () {
$('#flipper').addClass('flipper-h');
});
});
#2
$('#flipper.flipper-h').die(); //to prevent .live() event bubbling. I guess
$('#flipper.flipper-h').live('click', function () {
$(".l-l").animate({ "left": 0 }, 600, function () {
$('#flipper').removeClass('flipper-h');
});
});
with that code I have some problems:
1) after first page load, the code #2 has a little freeze before the animation starts
2) after second (and more) page load the #2 code doesn't fire. Why ?
EDIT
I've noticed that the code #2 is being invoked unlimited times (which's weird). But, I've fixed the 1) case by the code:
$('#flipper').click(function () {
if(!$(this).hasClass('flipper-h')) {
$(".l-l").animate({ "left": -267 }, 600, function () {
$('#flipper').addClass('flipper-h');
});
} else {
$(".l-l").animate({ "left": 0 }, 600, function () {
$('#flipper').removeClass('flipper-h');
});
}
});
but the problem 2) is still unsolved. Any ideas ?

EDIT3: Consider these two codes:
http://jsfiddle.net/2zEZT/2/
http://jsfiddle.net/2zEZT/3/
In first example, when you use remove button, elements are removed with elements that looks like same, but they are not. Events are lost.
In second one, elements are removed but click event is binded again after that...
EDIT2: Based on your edit, try to use this function instead. It could behaves better...
$('#flipper').click(function () {
if ($(this).hasClass('flipper-h')) {
$(this).removeClass('flipper-h');
$(".l-l").animate({
"left": 0
}, 600);
} else {
$(this).addClass('flipper-h');
$(".l-l").animate({
"left": -267
}, 600);
}
});
EDIT: I suggest that you still use jQuery 1.7 so I did a little investigation.
At first, you put event onclick on the #flipper.
Then you call die on #flipper.flipper-h element. Which should destroy all live events.
After that, you made a live event on #flipper.flipper-h element, which means that all elementes that exists and will exists will have this event.
Now first click:
animation left: -267 happens,
then callback does #flipper becomes #flipper.flipper-h,
then live event is binded to new #flipper.flipper-h,
Second click:
animation left: -267 happens, but it was already there, so nothing happens at all
then callback does #flipper becomes #flipper.flipper-h, so nothing happens again,
now event is still bubbling, so second animation left: 0 is triggered after 600ms (this is probably your freeze)
now callback removes .flipper-h
Now I dont know how exactly does your ajax works, but it seems that die function removes live event from #flipper forever. So it can't be triggered anymore...
die function doesnt prevent bubbling. It removes live events.
return false or event.stopPropagation does

Related

Components inserted into page using jquery's .load() function don't have a handle to javascript [duplicate]

On this page I have a jQuery popup window and thumbnail resizable images. If I mouse over on the thumbnails, the images are resizing perfectly. Also, when I click on the big yellow TV button "QuickBook TV" in the footer, the popup appears perfectly as I want it to.
However, when I click on the "Next" or "Prev" buttons, AJAX is used to load the new content and my jQuery no longer functions for the popup or thumbnail images. I have searched a number of forums looking for information on this issue, but due to having limited knowledge of jQuery I've been unable to understand what I need to do.
Following is the popup jQuery
$(document).ready(function() {
$(".iframe").colorbox({ iframe: true, width: "1000px", height: "500px" });
$(".inline").colorbox({ inline: true, width: "50%" });
$(".callbacks").colorbox({
onOpen: function() { alert('onOpen: colorbox is about to open'); },
onLoad: function() { alert('onLoad: colorbox has started to load the targeted content'); },
onComplete: function() { alert('onComplete: colorbox has displayed the loaded content'); },
onCleanup: function() { alert('onCleanup: colorbox has begun the close process'); },
onClosed: function() { alert('onClosed: colorbox has completely closed'); }
});
//Example of preserving a JavaScript event for inline calls.
$("#click").click(function() {
$('#click').css({ "background-color": "#f00", "color": "#fff", "cursor": "inherit" }).text("Open this window again and this message will still be here.");
return false;
});
});
And this is the thumbnails jQuery
$(function() {
var xwidth = ($('.image-popout img').width())/1;
var xheight = ($('.image-popout img').height())/1;
$('.image-popout img').css(
{'width': xwidth, 'height': xheight}
); //By default set the width and height of the image.
$('.image-popout img').parent().css(
{'width': xwidth, 'height': xheight}
);
$('.image-popout img').hover(
function() {
$(this).stop().animate( {
width : xwidth * 3,
height : xheight * 3,
margin : -(xwidth/3)
}, 200
); //END FUNCTION
$(this).addClass('image-popout-shadow');
}, //END HOVER IN
function() {
$(this).stop().animate( {
width : xwidth,
height : xheight,
margin : 0
}, 200, function() {
$(this).removeClass('image-popout-shadow');
}); //END FUNCTION
}
);
});
jQuery selectors select matching elements that exist in the DOM when the code is executed, and don't dynamically update. When you call a function, such as .hover() to add event handler(s), it only adds them to those elements. When you do an AJAX call, and replace a section of your page, you're removing those elements with the event handlers bound to them and replacing them with new elements. Even if those elements would now match that selector they don't get the event handler bound because the code to do that has already executed.
Event handlers
Specifically for event handlers (i.e. .click()) you can use event delegation to get around this. The basic principle is that you bind an event handler to a static (exists when the page loads, doesn't ever get replaced) element which will contain all of your dynamic (AJAX loaded) content. You can read more about event delegation in the jQuery documentation.
For your click event handler, the updated code would look like this:
$(document).on('click', "#click", function () {
$('#click').css({
"background-color": "#f00",
"color": "#fff",
"cursor": "inherit"
}).text("Open this window again and this message will still be here.");
return false;
});
That would bind an event handler to the entire document (so will never get removed until the page unloads), which will react to click events on an element with the id property of click. Ideally you'd use something closer to your dynamic elements in the DOM (perhaps a <div> on your page that is always there and contains all of your page content), since that will improve the efficiency a bit.
The issue comes when you need to handle .hover(), though. There's no actual hover event in JavaScript, jQuery just provides that function as a convenient shorthand for binding event handlers to the mouseenter and mouseleave events. You can, however, use event delegation:
$(document).on({
mouseenter: function () {
$(this).stop().animate({
width: xwidth * 3,
height: xheight * 3,
margin: -(xwidth / 3)
}, 200); //END FUNCTION
$(this).addClass('image-popout-shadow');
},
mouseleave: function () {
$(this).stop().animate({
width: xwidth,
height: xheight,
margin: 0
}, 200, function () {
$(this).removeClass('image-popout-shadow');
}); //END FUNCTION
}
}, '.image-popout img');
jQuery plugins
That covers the event handler bindings. However, that's not all you're doing. You also initialise a jQuery plugin (colorbox), and there's no way to delegate those to elements. You're going to have to simply call those lines again when you've loaded your AJAX content; the simplest way would be to move those into a separate named function that you can then call in both places (on page load and in your AJAX requests success callback):
function initialiseColorbox() {
$(".iframe").colorbox({
iframe: true,
width: "1000px",
height: "500px"
});
$(".inline").colorbox({
inline: true,
width: "50%"
});
$(".callbacks").colorbox({
onOpen: function () {
alert('onOpen: colorbox is about to open');
},
onLoad: function () {
alert('onLoad: colorbox has started to load the targeted content');
},
onComplete: function () {
alert('onComplete: colorbox has displayed the loaded content');
},
onCleanup: function () {
alert('onCleanup: colorbox has begun the close process');
},
onClosed: function () {
alert('onClosed: colorbox has completely closed');
}
});
}
Had the same problem before I was able to found the solution which worked for me.
So if anyone in future can give it a shot and let me know if it was right since all of the solutions I was able to find were a little more complicated than this.
So as said by Tamer Durgun, we will also place your code inside ajaxStop, so your code will be reinstated each time any event is completed by ajax.
$( document ).ajaxStop(function() {
//your code
}
Worked for me :)
// EXAMPLE FOR JQUERY AJAX COMPLETE FUNC.
$.ajax({
// get a form template first
url: "../FPFU/templates/yeni-workout-form.html",
type: "get",
success: function(data){
// insert this template into your container
$(".content").html(data);
},
error: function(){
alert_fail.removeClass("gizle");
alert_fail.addClass("goster");
alert_fail.html("Template getirilemedi.");
},
complete: function(){
// after all done you can manupulate here your new content
// tinymce yükleme
tinymce.init({
selector: '#workout-aciklama'
});
}
Your event handlers are being lost when you replace the content. When you set you hover events, jQuery is setting them on the events on the page currently. So when you replace them with ajax, the events are not associated with those elements because they are new.
To fix this you can either call the function that binds them again or you can instead set the event handler on the document as in this answer using $(document).on
That way the event is set on the document and any new elements will get the event called.
You Can User jQuery's delegate() method which Attach a handler to one or more events for all elements that match the selector, now or in the future, based on a specific set of root elements.In my case it's working as expected
this $(selector).click(function(e){}
become this after Using delegate() method
$( "body" ).delegate( "selector", "click", function(e) {}
Hope this will help ;)
You can use jQuery ajax's complete function after retrieving data form somewhere, it will see updated elements after ajax complete
This worked for me,
instead of:
$(document).ready(function(){
//code
});
I did:
$(document).on('mouseenter', function(){
//code
});
I'm late to the party but I would combine two of the answers. What worked for my specific needs was to incorporate the ajaxstop within the complete
complete: function () {
$( document ).ajaxStop(function() {
//now that all have been added to the dom, you can put in some code for your needs.
console.log($(".subareafilterActive").get().length)
})
}
Just an alternative.
$(window).on('load', _ => {
// some jQuery code ..
})
This binds any delegated handler to the window. It will fire once the window is fully loaded including all graphics/includes/hooks/requests not just the DOM.
$(document).ready(_ => ... preserves events to be fired after only the DOM is ready which does not apply on dynamically loaded content by AJAX. Either you can run a function or any event when a specific element is fully loaded by defining it as #Anthony Grist explained in his answer or bind your load event to the window as shown above.
https://api.jquery.com/load-event/
https://api.jquery.com/on/#on-events-selector-data-handler

jQuery scrollTo Plugin Flicker on scroll

I am using the jQuery plugin, scrollTo, to navigate through my webpage. When I click on the button, there seems to be a quick flicker and then resumes to continue scrolling normally. I saw other solutions where they call the preventDefault() method, but I don't know how I would implement it in my case. Here is my method that is called when a link is clicked.
function btn_Pressed(goTo){
$(goTo).ScrollTo({
duration: 1200
});
}
It is a generic method that will scroll to whatever anchor is passed as an argument. What am I doing wrong. THIS FLICKER IS SO UGLY!
I did find a solution, however, I don't know if it is the most efficient one. I made a function that handles each button click so I could explicitly call and handle each scroll all while calling preventDefault(). Here is a sample...
$(function(){
$("#btn_home").click(function(e) {
$('#myAffix').ScrollTo({
duration: 1200,
});
e.preventDefault();
});
$("#aboutUs").click(function(e) {
$('#anchorOne').ScrollTo({
duration: 1200,
});
e.preventDefault();
});
$("#btn_home").click(function(e) {
$('#myAffix').ScrollTo({
duration: 1200,
});
e.preventDefault();
});
});

Script running only once

I'm trying to make a side menu that opens and closes from the left when you press the menu button.
Got the css, html code running properly but I can't figure out what I'm doing wrong with the script. It works perfectly but only once: When I press the menu button it comes out, press it again and it goes back just as intended. The problem is if I press it again it shows and it goes back by itself. Can anyone help me?
Here is my script:
$(document).ready(function(){
$('.menu-icon').click(function(){
$('#navigator').animate({left:'0px'},200);
$(this).animate({left:'250px'},200);
$('.menu-icon').click(function(){
>$('#navigator').animate({left:'-250px'},200);
>$(this).animate({left:'0px'},200);
});
});
>});
You have placed a click handler inside a click handler so it will run multiple times. Twice first time, then three times, then four times etc.
You need to have a single handler and decide how to animate based on the current state of the element. e.g. something like the following (not tested):
$(document).ready(function () {
$('.menu-icon').click(function () {
if ($('#navigator').css("left") != "0px") {
$('#navigator').animate({
left: '0px'
}, 200);
$(this).animate({
left: '250px'
}, 200);
} else {
$('#navigator').animate({
left: '-250px'
}, 200); > $(this).animate({
left: '0px'
}, 200);
}
});
});
I would suggest testing the "current state" using a class you toggle on the element as testing css values is notoriously unreliable during animation.
e.g. something like:
if ($('#navigator').toggleClass("open").hasClass("open")) {
Here you are attaching the click event listener two times. One normal and one after clicking, thats why its happening use jquery toggle
or use in this way
$(document).ready(function(){
$('.menu-icon').click(function(){
var navigator = $('#navigator');
if(navigator.offset().left == 0)
{
navigator.animate({left:'-250px'},200);
$(this).animate({left:'0px'},200);
}
else
{
navigator.animate({left:'0px'},200);
$(this).animate({left:'250px'},200);
}
});
});

How can I prevent a custom event from being triggered repeatedly – or can I "reset" the jQuery .one() function?

I have some code, that checks for the visibility of an element on the screen. As soon as it comes in sight by scrolling the page a custom event is triggered. This custom event starts an animation. To prevent this animation to be started over and over the function that starts it is only started once. For that I used the jQuery function .one().
The function to check if element is visible:
checkScrollPos = function() {
if (objTopPos - scrollPos <= windowHeight / 2) {
$(document).trigger('objVisible');
}
}
The function to listen for the event:
evtListener = function() {
//startAnimation() should only be started once
$(document).one(
{
'objVisible': function(event) {
startAnimation();
}
}
);
}
Here it all happens:
$(document).ready(function() {
evtListener();
$(window).scroll(function () {
scrollPos = $(document).scrollTop();
checkScrollPos();
}
}
Now this all works fine but I extended the checkScrollPos() function to also check if the element gets out of sight again, to then stop the animation. That works fine to. Problem is, as the events trigger, the event-bound functions only are executed one time. So when you scroll teh element in sight, then out of sight and then in sight again the animation will not be executed again (what is the correct behaviour of course). Now I would like to have it that the events are triggered exactly one time but EVERYTIME the element gets in or out of sight and not just one time at all. So basicly I need some kind of reset for the
$(document).one()
function – so that everytime the element gets out of sight, I can use the .one() function again. Is there any way to do that?
You have to bind the objVisible event every time the element disappears.
Just call evtListener() after the element is out of sight, so that the objVisible event is bound again.
Your code would be something like this:
checkScrollPos = function() {
if (objTopPos - scrollPos <= windowHeight / 2) {
$(document).trigger('objVisible');
}
if (/* your condition to check if element is out of sight */) {
evtListener();
}
}

jQuery: Prevent stacking animations

I know there are several other posts with solutions to this, but my current problem is a little different.
I have two events on an element - mouseenter and mouseleave. The first changed the color of my element to light and the other back to dark, this makes a flashing effect.
The problem is when I go in and out a couple of times the events stack and it flashes many times even if no new events are triggered. I would like to prevent that, but .stop() does not help.
Here's the catch: I would like to trigger 1 flash no matter what, but not more than 1. So when someone moves in / out - the event mouseenter will be fired, after it mouseleave and after it nothing.. until another in / out is triggered.
I guess this could be made by locking (not listening for) new events when in / out is triggered up until the effect has finished, but I don't know how to do without unbinding and binding it again. Isn't there any lockEvent() or something?
Have you already used .stop(true) or .stop(true, true)?
there is pseudo-class in jQuery ":animated"
you can use it on first mouseenter even like:
if ( $(this).is(':animated')) {
return false;
}
to prevent additional animation
You can try just setting a bool var and firing only if false...
var anim = {
animating: false,
over: function(){
if(!anim.animating)
{
anim.animating = true;
// do you animation here
// and set your animating bool to false before calling outro...
$('#elem').animate({/*some css change*/ }, 1000, function(){
anim.animating = false;
anim.out();
});
}
},
out: function(){
if(!anim.animating)
{
anim.animating = true;
//do your outro animation here
$('#elem').animate({/*some css change*/ }, 1000, function(){
anim.animating = false;
});
}
}
};
then have your listener call anim.over and anim.out...
$('#elem').on('mouseenter', function(){
anim.over();
}).on('mouseleave', function(){
anim.out();
});
This way you will call animation on enter and it will automatically fire off the outro animation when the intro completes.

Categories

Resources