animation starts with delay - javascript

i have writen script which loads content from external php file. i'm using jquery1-9-1. my script works normal, except that moment when i'm clicking on button second time. there is delay for 0.5s before the animation starts. i think i know what is the problem and where is it. $("#header").animate({marginTop: "10px"... must execute just on the first click. after this clicked once, it must be deactivated. who knows how to solve it? don judge me so harsh and sorry my english
$(document).ready(function () {
var content = $("#content");
$("#main_menu a").click(function () {
var id = this.id;
$("#header").animate({
marginTop: "10px"
}, 500, function () {
$("#content").fadeOut(500, function () {
$("#content").load(id + ".php")
$("#content").fadeIn(500)
})
})
})
})

I have to ask, what is the point of caching content = $("#content") if you then refuse to use it and just call $("#content") repeatedly later?
Anyway, you need a variable to tell if it's the first run or not:
$(function () {
var content = $("#content"), isfirst = true;
$("#main_menu a").click(function () {
var id = this.id,
reveal = function() {
content.fadeOut(500, function () {
content.load(id + ".php")
content.fadeIn(500)
});
};
if( isfirst) $("#header").animate({marginTop: "10px"}, 500, reveal);
else reveal();
isfirst = false;
});
});

You need to track whether or not it has loaded, in that case. A simple variable and some closure should do it:
var isLoaded = false;
$("#main_menu a").click(function () {
var id = this.id;
if (!isLoaded) {
$("#header").animate({
marginTop: "10px"
}, 500);
isLoaded = true;
}
$("#content").fadeOut(500, function () {
$("#content").load(id + ".php")
$("#content").fadeIn(500)
})
});

Related

Reverse jQuery effect after a given time

one quick question!
I am using the following code which does a "flip" card effect to flip a specific div element, when a certain link is mouse clicked. Is it possible to make the "flip" effect reverse after some time? Exactly as if I was clicking again with the mouse, but timed. I can do it now by cliking, but I would like to time it.
$(document).ready(function () {
$('.flip_card').click(function () {
var x = $(this).attr("id");
var i = x.substring(10);
$('.flip' + i + '').find('.card').toggleClass('flipped');
});
});
I have tried using the jquery functions delay() or settimeout, but I can only achieve that the first "flip" effect is delayed and happens after certain time. That is not what I want...
I hope my question is understanble enough.
Many thanks!
Try this.
$(document).ready(function () {
$('.flip_card').click(function () {
var x = $(this).attr("id");
var i = x.substring(10);
var ele = '.flip' + i + '';
$(ele).find('.card').toggleClass('flipped');
setTimeout(function(){
$(ele).find('.card').toggleClass('flipped');
}, 1000);
});
});
Try utilizing .queue()
$(document).ready(function () {
$(".flip_card").click(function () {
var x = this.id;
var i = x.substring(10);
$(".flip" + i).find(".card").toggleClass("flipped")
.queue("reset", function() {
setTimeout(function() {
$(".flip"+ i + " .card.flipped:eq(-1)").toggleClass("flipped");
// set duration here
}, 3000);
}).dequeue("reset");
});
});
You can use setTimeout(), but you should keep track of the timer ID so you can cancel it if the user clicks again before the timeout has executed. You can use the .data() function to store the timer ID so each card keeps track of its own timer ID.
$(document).ready(function () {
$('.flip_card').click(function () {
var i = $(this).attr('id').substring(10);
var $card = $('.flip' + i).find('.card');
// Clear the timeout if there is one.
var timerId = $card.data('timerId');
if (timerId) {
clearTimeout(timerId);
}
// Flip the card.
if (!$card.hasClass('flipped')) {
$card.addClass('flipped');
// Set the timeout so the card is flipped back after 3 seconds.
$card.data('timerId', setTimeout(function () {
$card.removeClass('flipped');
}, 3000));
} else {
$card.removeClass('flipped');
}
});
});
jsfiddle
How about something this simple. Just chaining should make it.
$(document).ready(function () {
$('.flip_card').bind('click', function() {
var x = $(this).attr("id");
var i = x.substring(10);
var ele = '.flip' + i + '';
$(ele).find('.card').toggleClass('flipped').delay(3000).toggleClass('flipped');
});
});

Scraping an infinite scroll page stops without scrolling

I am currently working with PhantomJS and CasperJS to scrape for links in a website. The site uses javascript to dynamically load results. The below snippet however is not getting me all the results the page contains. What I need is to scroll down to the bottom of the page, see if the spinner shows up (meaning there’s more content still to come), wait until the new content had loaded and then keep scrolling until no more new content was shown. Then store the links with class name .title in an array. Link to the webpage for scraping.
var casper = require('casper').create();
var urls = [];
function tryAndScroll(casper) {
casper.waitFor(function() {
this.page.scrollPosition = { top: this.page.scrollPosition["top"] + 4000, left: 0 };
return true;
}, function() {
var info = this.getElementInfo('.badge-post-grid-load-more');
if (info["visible"] == true) {
this.waitWhileVisible('.badge-post-grid-load-more', function () {
this.emit('results.loaded');
}, function () {
this.echo('next results not loaded');
}, 5000);
}
}, function() {
this.echo("Scrolling failed. Sorry.").exit();
}, 500);
}
casper.on('results.loaded', function () {
tryAndScroll(this);
});
casper.start('http://example.com/', function() {
this.waitUntilVisible('.title', function() {
tryAndScroll(this);
});
});
casper.then(function() {
casper.each(this.getElementsInfo('.title'), function(casper, element, j) {
var url = element["attributes"]["href"];
urls.push(url);
});
});
casper.run(function() {
this.echo(urls.length + ' links found:');
this.echo(urls.join('\n')).exit();
});
I've looked at the page. Your misconception is probably that you think the .badge-post-grid-load-more element vanishes as soon as the next elements are loaded. This is not the case. It doesn't change at all. You have to find another way to test whether new elements were put into the DOM.
You could for example retrieve the current number of elements and use waitFor to detect when the number changes.
function getNumberOfItems(casper) {
return casper.getElementsInfo(".listview .badge-grid-item").length;
}
function tryAndScroll(casper) {
casper.page.scrollPosition = { top: casper.page.scrollPosition["top"] + 4000, left: 0 };
var info = casper.getElementInfo('.badge-post-grid-load-more');
if (info.visible) {
var curItems = getNumberOfItems(casper);
casper.waitFor(function check(){
return curItems != getNumberOfItems(casper);
}, function then(){
tryAndScroll(this);
}, function onTimeout(){
this.echo("Timout reached");
}, 20000);
} else {
casper.echo("no more items");
}
}
I've also streamlined tryAndScroll a little. There were completely unnecessary functions: the first casper.waitFor wasn't waiting at all and because of that the onTimeout callback could never be invoked.

clearInterval not working as I expect it too

I made a demo which is here. All you have to do is start typing in the text field, make sure you have the console open. So as you type, you'll instantly see the OMG Saved, and the counter in the console will go nuts.
Now click the button, watching the console you should see something like 11 or some other value, but you'll also see the counter reset and continues going. I do not want this. I want the counter to stop, I have clicked a button and while the page hasn't refreshed, the counter should stop if I understand these docs on setInterval().
the app I am developing which uses code very similar to this, does not refresh as most single page apps don't. So it is imperative that I have control over this setInterval.
So my question is:
How do I reset the counter such that, until I type again in the input box OR if the input box element cannot be found the flash message does not show up, the interval is set back to 0.
update
The following is the JavaScript code, which is run on the link provided above.
var ObjectClass = {
initialize: function() {
$('#flash-message').hide();
},
syncSave: function() {
$('#content').keypress(function(){
SomeOtherClass.autoSave = setInterval( function(){
$('#flash-message').show();
$('#flash-message').delay(1000).fadeOut('slow');
}, 500);
});
},
listenForClick: function() {
$('#click-me').click(function() {
console.log(SomeOtherClass.autoSave);
clearInterval(SomeOtherClass.autoSave);
});
}
};
var SomeOtherClass = {
autoSave: null
};
ObjectClass.initialize();
ObjectClass.syncSave();
ObjectClass.listenForClick();
You have to put this
clearInterval(SomeOtherClass.autoSave);
before this line:
SomeOtherClass.autoSave = setInterval( function(){
So that you kill the previous interval and you ahve ONLY ONE interval at the same time
Your code will be:
var ObjectClass = {
initialize: function () {
$('#flash-message').hide();
},
syncSave: function () {
$('#content').keypress(function () {
clearInterval(SomeOtherClass.autoSave);
SomeOtherClass.autoSave = setInterval(function () {
$('#flash-message').show();
$('#flash-message').delay(1000).fadeOut('slow');
}, 500);
});
},
listenForClick: function () {
$('#click-me').click(function () {
console.log(SomeOtherClass.autoSave);
clearInterval(SomeOtherClass.autoSave);
});
}
};
var SomeOtherClass = {
autoSave: null
};
ObjectClass.initialize();
ObjectClass.syncSave();
ObjectClass.listenForClick();
What you need to do is use a timeout instead of an interval, like this:
var ObjectClass = {
initialize: function() {
$('#flash-message').hide();
},
syncSave: function() {
$('#content').keypress(function(){
SomeOtherClass.autoSave = setTimeout( function(){
$('#flash-message').show();
$('#flash-message').delay(1000).fadeOut('slow');
}, 500);
});
},
listenForClick: function() {
$('#click-me').click(function() {
console.log(SomeOtherClass.autoSave);
if(typeof SomeOtherClass.autoSave === 'number'){
clearTimeout(SomeOtherClass.autoSave);
SomeOtherClass.autoSave = 0;
}
});
}
};
var SomeOtherClass = {
autoSave: 0
};
ObjectClass.initialize();
ObjectClass.syncSave();
ObjectClass.listenForClick();

Call one event on a set of matches

I do what something like:
$('div > img').onAll('load', function() { alert('Loaded!') })
Which would alert "Loaded!" only once
I don't want this:
$('div > img').on('load', function() { alert('Loaded!'); });
because this would call the event after every single image has been loaded
Is there any ready function in jQuery that calls an event on a set of matches? Or do I have to write a custom function for it?
Create your own method
$.fn.onAll = function(ev, callback) {
var xhr = [];
this.each(function() {
var def = new $.Deferred();
var ele = document.createElement(this.tagName.toLowerCase());
ele['on'+ev] = function() {
def.resolve();
}
ele.src = this.src;
xhr.push(def);
});
$.when.apply($, xhr).then(callback);
return this;
}
to be used as
$('div > img').onAll('load', function() { alert('Loaded!'); });
FIDDLE
Try this
var $images = $("div > img")
, imageCount = $images.length
, counter = 0;
// one instead of on, because it need only fire once per image
$images.one("load",function(){
// increment counter everytime an image finishes loading
counter++;
if (counter == imageCount) {
// do stuff when all have loaded
alert('Loaded!');
}
}).each(function () {
if (this.complete) {
// manually trigger load event in
// event of a cache pull
$(this).trigger("load");
}
});
try something like this
$('body').on('load','div > img',function() { alert('Loaded!') });
Happy Coding :)

setInterval and clearInterval javascript not working as needed

I have the following code partially working. I am newbie in javascript so please don't blame me if my approach is not the best.
window.url_var = "status.htm";
window.elem = "#e1";
function menu_item(){
$(window.elem).click(function (event)
{
$("#divTestArea1").load(window.url_var);
});
}
$("#e1").click(function (event)
{
event.preventDefault();
window.url_var = "demo2.txt";
window.elem = "#e1";
$("#divTestArea1").load(window.url_var);
auto_refresh = setInterval(menu_item(), 5000);
});
$("#e2").click(function (event)
{
event.preventDefault();
window.url_var = "status.htm";
window.elem = "#e2";
$("#divTestArea1").load(window.url_var);
auto_refresh = setInterval(menu_item(), 5000);
});
$("#e3").click(function (event)
{
event.preventDefault();
window.url_var = "form.htm";
window.elem = "#e3";
clearInterval(auto_refresh);
$("#divTestArea1").load(window.url_var);
});
jQuery(document).ready(function() {
$("#divTestArea1").load(window.url_var);
auto_refresh = setInterval(menu_item(), 5000);
});
Whenever I click elements e1 and e2, the setInterval works as expected and as soon as I click element e3, the element cease to be reloaded.
That's the behavior I want so far. But I also wants to start the setinterval again if e1 or e2 get's again clicked.
the last is what it's not working on the above code.
I will appreciate if you could point me in the right direction.
I have come to this code after seeing some of the answers to my original question (thanks to everyone). To clarify my original idea, I need to update some items on my web page on a regular basics but the content can be change with some menu and also some of the contents like a form should not be updated.
window.url_var = "demo2.txt";
var auto_refresh = null;
function setRefresh() {
var self = this;
this.bar = function() {
if(window.url_var != ""){
$("#divTestArea1").load(window.url_var);
auto_refresh = setTimeout(function() { self.bar(); }, 5000);
}
}
this.bar();
}
$("#e1").click(function (event)
{
event.preventDefault();
window.url_var = "demo2.txt";
setRefresh();
});
$("#e2").click(function (event)
{
event.preventDefault();
window.url_var = "status.htm";
setRefresh();
});
$("#e3").click(function (event)
{
event.preventDefault();
window.url_var = "form.htm";
$("#divTestArea1").load(window.url_var);
window.url_var = "";
});
$(document).ready(function() {
setRefresh();
});
Try using 2 different variables and clearing all if needed. This is: auto_refresh1 and auto_refresh2. Each time you call setinterval, it creates a new timer with a new id. You are overwriting auto_refresh variable and the timer before that will still fire.
Or you can store the setinterval in a hash object and run through and clear them all.
I'm unclear as to what exactly it is that you're trying to do here. Nevertheless, I've rewritten your code a bit to make some improvements (and fix one glaring bug in your code involving the setInterval calls).
var url_var = "status.htm",
elem = "#e1",
$destination = $("#divTestArea1"),
auto_refresh;
function menu_item() {
$(elem).bind("click", function (e) {
$destination.load(url_var);
});
}
function load() {
$destination.load(url_var);
}
function set(url, id) {
url_var = url;
elem = id;
}
function setRefresh() {
return setInterval(menu_item, 5000);
}
function handleClick(e) {
e.preventDefault();
set(e.data.url, e.data.id);
load();
auto_refresh = setRefresh();
}
$("#e1").on("click", {
url: "demo2.txt",
id: "#e1"
}, handleClick);
$("#e2").on("click", {
url: "status.htm",
id: "#e2"
}, handleClick);
$("#e3").on("click", function (e) {
e.preventDefault();
set("form.htm", "#e3");
clearInterval(auto_refresh);
load();
});
$(document).ready(function () {
load();
auto_refresh = setRefresh();
});
I'm guessing that maybe those setInterval calls should actually be setTimeout calls? Why would you want to bind a "click" event handler over and over again?
EDIT #1: Switched to jQuery's currently preferred on method from the bind method, included use of event data parameter to further abstract event handling code.

Categories

Resources