I have spend a lot of time think about this and tried different things now. I want to scrape a webpage with multiple pages but the page does not reload on page change. Instead, some container data is changed on each changed page. The most difficult thing to do is know when to click the next page button.
Someone might think that this is pretty easy and I thought the same and started off by doing:
$('.pagn a').each(function() {
console.log(`Loop counter`)
$(this).click()
//Code to scrape the new page
})
Now, the loop runs 13 times but only one page is changed. This is because the pagination itself is inside the container that reloads so all other button presses are basically ignored.
To tackle this I needed some kind of a check that makes sure that the new content has loaded before proceeding but if I try to do something like:
$('.pagn a').each(function() {
console.log(`Loop counter`)
while (someConditionToCheckIfPageLoaded) {
}
$(this).click()
//Code to scrape the new page
})
This would be an infinite loop because JavaScript is single threaded and the code to change the condition never fires.
I also tried this which I now know is incorrect.
The indicator for page being loaded is if the button URL matches the page URL.
$('.pagn a').each(function() {
let visitedURL = [];
if ($(this).attr('data-url')) {
let button = $(this)
buttonURL = "https://www.ebay.com/myb/PurchaseHistory#" + $(this).attr('data-url');
(function wait() {
button.click()
if (buttonURL == location.href && !visitedURL.includes(button.html())) {
console.log(button.html())
button.click()
visitedURL.push(button.html())
console.log(buttonURL);
console.log(location.href);
//Scrape page
} else {
setInterval(wait, 5000);
}
})();
}
})
This also only changes one page.
If someone has been able to scrape webpages with multiple pages with JavaScript please let me know how.
Edit1:
Also, I am not sure why this creates an infinite loop as well:
let glbElements = []
$('.pagn a').each(function() {
glbElements.push($(this))
})
for(let i = 0 ; i<glbElements.length; i++){
console.log(`Loop Counter`)
setTimeout(function(){
console.log(`Inside SetTimeout`)
glbElements[i].click()
glbElements.splice(i,1)
},2000)
}
Lopp Counter *5
Inside SetInterval -- Keeps printing
You can use the setTimeout() function to wait after a user clicks a button.
Like this:
<a href='newpage.html'><button id='click'>Click!</button</a>
$('#click').click(function() {
setTimeout(function() {
// code you want executed after page is loaded
}, 100);
});
So I have a fiddle with two pulsing animations running at different times.
http://jsfiddle.net/JuFxn/16/
The code for the pulse is here. There is more in the fiddle so please check it out.
function fadeItIn() {
var child;
child = 4;
setTimeout(fadeIn, 3000);
function fadeIn() {
$("#child" + child).fadeIn(175);
--child;
if (child >= 0) {
// Continue fading in
setTimeout(fadeIn, 175);
} else {
// Start fading out
++child;
setTimeout(fadeOut, 175);
}
}
function fadeOut() {
$("#child" + child).fadeOut(175);
++child;
if (child <= 4) {
// Continue fading out
setTimeout(fadeOut, 175);
} else {
// Start over again
setTimeout(fadeIn, 3000 - 1575);
}
}
}
The issue I'm having is that when the tab becomes inactive, the timings of the two pulses desync and go off pretty far from each other. I did some research and found this
How can I make setInterval also work when a tab is inactive in Chrome?
They seem to fix the problem by implementing a real world counter in and adding the value of the counter during each cycle and having the div move based on the distance generated by the counter. Would implementing something like that fix the problem I am having? How would I even use it? I think the problem is arising from the use of the setTimeout on the second function.
setTimeout(fadeItInDoom, 500);
If I take out the setTimeout and make it so the two pulses execute at the same time, the timings never go off.
So I ended up figuring out a fix to make it stay in sync.
http://jsfiddle.net/bwCmk/
I changed the animation code entirely so that it is running in jQuery. The fix however comes in how I dealt with changing to the next animation. I just made a different function for each pulsing element and had the next one called at the end of the previous function. So:
FunctionA {
code
functionB();
}
FunctionB {
code
functionC();
}
etc
it worked. Just putting this up so that if anyone else makes something along these lines, they can find a fix for it. Thanks to everyone who answered.
My website works in a way so that any links clicked do not load a new page but however trigger a .load() event into a div named "content".
Everything has been nice and dandy but now I have run into a small problem.
On one of the content pages, I have the following code:
$('.count').each(function () {
$this = $(this);
countdown = setInterval(function(){
countnow = parseInt($('.remain', $this).html());
$('.remain', $this).html(countnow-1);
}, 1000);
return false;
});
The code works... it works very well. But when I load that same page again, it seems like the code is running twice because the seconds are going down by 2 at a time. Then when I load it again, it's going down by 3 seconds at a time. Another load, and it goes down by 4 seconds at a time. I load it a couple more times and it goes down faster then I can read.
I tried giving the .count divs their own unique id's (the .remain div is nested inside the .count div), even when pages are subsequently loaded the id is still entirely different and this did not fix my problem. I also tried putting clearInterval(countdown) right before the function but that just made it stop working entirely. Any suggestions?
And yes I know the countdown doesn't currently stop when it reaches 0.
Try this:
var countdown;
$('.count').each(function () {
$this = $(this);
if (!countdown)
countdown = setInterval(function(){
countnow = parseInt($('.remain', $this).html());
$('.remain', $this).html(countnow-1);
}, 1000);
return false;
});
I am a JS novice so go easy on me here. But I wrote a simple slideshow and it seems to be running very slow. The code below takes about 2-4 seconds to load locally on my own machine. Wondering what is causing the delay. Let me know, thanks!
function slideshow(){
$("#1").animate({top: "50px",}, 500).delay(2000);
$("#1").animate({top: "400px",}, 500);
$("#2").animate({top: "50px",}, 500).delay(2000);
$("#2").animate({top: "400px",}, 500);
$("#3").animate({top: "50px",}, 500).delay(2000);
$("#3").animate({top: "400px",}, 500);
$("#4").animate({top: "50px",}, 500).delay(2000);
$("#4").animate({top: "400px",}, 500);
$("#5").animate({top: "50px",}, 500).delay(2000);
$("#5").animate({top: "400px",}, 500);
slideshow();
}
Each ID represents a different image.
The big problem with your code, since none of the other answers seem to have talked about it yet, is that the last line of slideshow() calls itself recursively, which will lead to a stack overflow. Don't do this:
function slideshow() {
// animate code
slideshow();
}
Instead, if you want it to run repeatedly, use setTimeout() to queue another execution of the function x milliseconds later:
function slideshow() {
// animate code
setTimeout(slideshow, 3500);
}
The way you had it, none of the functions ever actually finishes. With setTimeout(), each invocation of slideshow() does finish, and then a separate one runs after the specified delay. I'd make the delay big enough that the next invocation occurs after the current animations finish, otherwise you'll be queuing up more and more animations faster than they run.
UPDATE: jQuery maintains separate animation queues for each element, which means that the animations on your five elements will run simultaneously. Some of the other answers already provide ways of running the animations in sequence one at a time, but here is how I'd do it:
$(window).on("load",function() {
// cache a jQuery object containing the elements to animate
// (note you don't need their ids if you use their class)
var $imgs = $('img.slideshow-image'),
i = 0;
function slideShow() {
// start animation for "current" img
$imgs.eq(i).show(1)
.animate({top: "50px",}, 500)
.delay(2000)
.animate({top: "400px",}, 500)
.hide(1, function() {
i = (i+1) % $imgs.length;
setTimeout(slideShow, 500);
});
}
slideShow();
});
Working demo: http://jsfiddle.net/bARwb/
I've wrapped the code in a load handler both to remove the need for an inline onload= attribute and as a convenient way of keeping the code out of the global scope (if you do it this way don't forget to remove onload="slideShow()" from your body tag).
I've added .show() and .hide() calls (with a duration so that they join the animation queue) so that the img elements will have display:none in between animations because otherwise with your position:relative style you can't see any but the first (but changing to position:absolute would prevent them getting cropped by their parent's overflow:hidden).
When the animation finishes for an element, the callback from .hide() increments i to refer to the next element's index (but checks for when it goes past the last element) and then uses setTimeout() to queue the animation for that next element.
You have some duplication in there, and also some incorrect assumptions.
When you call .animate in jQuery, you can specify a callback that will be called when the animation is complete. This is the place to put your "next step".
So in this example:
animate the image
when complete, wait 2 seconds
after 2 seconds, animate the image
when complete, call the function with the next image
This is how it looks
var images = ['#1', '#2', '#3', '#4', '#5'];
function slideshow(index){
if (index >= images.length) {
index = 0;
}
var image = images[index];
$(image).animate({top: "50px",}, 500, function () {
window.setTimeout(function () {
$(image).animate({top: "400px",}, 500, function () {
slideshow(index + 1);
});
}, 2000);
});
}
my guess is that you are setting your frames to 2 seconds (2000). Try something speedier like 50 and see what you see. I'm not sure if that's the frame delay or the 500 but if either of those represents how long you are waiting between frame changes it's way too long.
Other than the intentional delays in your code, i do not see anything that would cause the slow loading. It may be the rest of the page. I would check to see how large your images are and any other files that may be downloading before the JavaScript slideshow function executes.
As a side note, it is strange that you call slideshow from within the slideshow function.
You could try something like this:
var intervalValue = setInterval( "slideshow()", 2000 );
var slideshow_imageindex = 1;
function slideshow()
{
//check if imageindex is greater than the number of images available (5 is an example)
if (slideshow_imageindex > 5)
{
slideshow_imageindex = 1;
}
//hide image below, change image src, then move image so that it is visible again
$("#1").animate({top: "400px",}, 500).attr('src','img/Slideshow-Audio-Trsfr'+slideshow_imageindex+'.png').animate({top: "50px",}, 500);
//increase image index
slideshow_imageindex++;
}
You will only need a single img (i kept your "id=#1" img), and every 2 seconds the image is hidden, it changes and the it is shown again. Only things you have to do: name the images so that only the number changes, like:
img/Slideshow-Audio-Trsfr1.png
img/Slideshow-Audio-Trsfr2.png
img/Slideshow-Audio-Trsfr3.png
img/Slideshow-Audio-Trsfr4.png
img/Slideshow-Audio-Trsfr5.png
and then use the number of images in the "if" within the function. It's late here in italy, hope i didn't forget anything :)
I've included some JavaScript from a third party in my page. This adds the following element to the page some time after the page is loaded:
<a class="foo">some link</a>
I need to ensure that this is changed to:
<a class="bar">some link</a>
ASAP after the element is added to the page. I tried adding the following to a JQuery ready handler
$('a.gullSearchBtn').removeClass('gullSearchBtn').addClass('roundButton');
But this executes before the element is added and therefore doesn't work. I've searched the web and it seems like the jQuery feature known as "livequery" might be the solution to my problem, but I can't seem to get it to work.
Binding to the DOMNodeInserted or DOMSubtreeModified may help accomplish this. But according to the following post this won't work with IE
How to detect new element creation in jQuery?
You could just go native styles and use a setTimeout function to check if it exits. But this will only work if you have a unique way to identify that element eg: it is the only anchor element with the foo class
My Recommended Loop
$(document).ready(function(){
checkTimer();
});
function checkTimer(){
var ele = $('a.foo');
if(ele.length == 0){
setTimeout(function(){
checkTimer();
},100);
}
else {
ele.attr('class','bar');
}
}
Some will suggest that you use a setInterval() which provides the same functionality as the loop above. I know from personal experience how prone this is to breaking though, but here is the code for that version.
setInterval() Loop
var timer;
$(document).ready(function(){
timer = setInterval(function(){
checkTimer();
},100);
});
function checkTimer(){
var ele = $('a.foo');
if(ele.length != 0){
ele.attr('class','bar');
clearTimeout(timer)
}
}
Have you considered this?
original CSS
.roundButton {
[your rules]
}
changed CSS
.gullSearchBtn, .roundButton {
[your rules]
}
demo: http://so.devilmaycode.it/change-css-classes-of-element-added-to-dom-at-runtime
$(function() {
$('.foo').click(function(e) {
$('body').append('<p class="gullSearchBtn">text</p>');
return false;
});
setInterval(function() {
if ($('.gullSearchBtn').length)
$('.gullSearchBtn').removeClass('gullSearchBtn').addClass('roundButton');
//clearInterval() optional if you don't need to loop anymore...
}, 100);
});