Rails Javascript Database Doubt - javascript

I am trying to display a set of images at certain time intervals in my rails application. Now i am using javascript for this and taking the timings from the user for the time between each slide to be displayed. Now for that i am using the setTimeout function of javascript in which i am trying to fetch the time from the database,ie, my table named slides.
This is my code snippet for preloading images
var preloaded = new Array();
for (var x = 0; x < 10; x++)
{
preloaded[x] = new Image();
preloaded[x].src = "/images/pausch/img"+x+".gif";
}
This is my snippet of the image changing function
function slideit(){
//if browser does not support the image object, exit.
if (!document.images)
return;
document.images.slide.src=eval("preloaded["+step+"].src");
if (step<10)
step++;
else
step=0 ;
<% #slides.each do |slide| %>
setTimeout("slideit()",'<%= slide.time.to_i %>')
<% end %>
}
However the images are changing are some random times and not according to the time stored. Can anyone suggest whats wrong?

Try removing the setTimeout() call from inside the function, and put a call to (say) setInterval(slideit,1000) somewhere outside the function:
....
document.images.slide.src = preloaded[step].src;
if (step<10) step++;
else step=0;
}
setInterval(slideit,1000);
This will cause slideit() to be called every 1000 miliseconds, rather than assigning multiple timeouts each time the function is called.
Note I also removed the eval() call and some extra quotes from your preloaded[step].src line - It won't affect the timeout stuff, but you shouldn't need eval here because the contents of the array is just a string (and for security reasons it's generally good to avoid using eval() if you can).
Edit: Just saw that you want different timeouts for each image. I would do this with a single call to setTimeout():
....
document.images.slide.src = preloaded[step].src;
setTimeout(slideit,timeouts[step]);
if (step<10) step++;
else step=0;
}
For this solution, you'll want to initialise an array called timeouts where each entry timeouts[x] contains the number of miliseconds to display image x.

Related

determine content of setinterval callback

I've encountered a very badly designed website, and most of the "dynamic" content on the site is changed within setTimeout/setInterval functions.
There is one very annoying setInterval function which checks page activity very quickly, and I would like to override this function.
What I tried is clearing all the setInterval values, one by one to check if the function stopped. Also, clearing all the possible setInterval values like this: for(let i = 0; i < 1000; i++) clearInterval(i);, stops the "dynamic" page rendering, WHICH I DONT WANT TO
Question: 1. is there any way to look into the interval or timeout function and clear them?
2. is there a better way?
My current solution: I'm overriding the setInterval and setTimeout before page loaded, and log the function .toString() within.
The short answer is no, you cannot determine anything about the setTimeout/setInterval callback given a timerId. It sounds as if you don't have access to edit the underlying Javascript to prevent this action. If you can get your JS to load before the code in the page, then what you can do is replace setInterval or setTimeout with your own code, where you can increase the interval to whatever you want. For example:
let setTimeoutOld = setTimeout;
setTimeout = (cb, interval) => {
if (interval < 1000) {
interval = 1000;
}
setTimeoutOld(cb, interval);
}
Now if the page does something like:
setTimeout(() => { console.log('fired') }, 1);
The timeout won't fire until at least 1000ms have passed. If you only wanted to modify a specific setTimeout based on the contents of the cb, you could do what you mentioned in your work-around: calling .toString() on the function and comparing it to some previously generated .toString() (partial or complete) and then doing whatever you wanted.
I assume you have access to code wherever it's setting timeout or interval.
So just take a global array and push it's output to it. Then iterate that array to clear everything.
For ex.
timeouts = [];
now, in code where there's timeout like
var timeout = setTimeout(<callback> , <interval> ); // push it's output to that global.
timeouts.push(timeout);
Then at the very end clear that.
for(time of timeouts) {
clearTimeout(time);
}
Similarly, for Interval.
Hope this is what you are looking for.

How to go through an array of url and parse it?

I have an array of URL's and I want to go to every page to parse some information. I do:
var numbers = ["1111", "2222", "3333"];
function parse(page){...
}
function set(page){
console.log(page);
window.location = page;
parse (page);
}
for (j=0,m = numbers.length; j<m; j++){
page="http://www.*****/*****/"+numbers[j]+"/*****/";
setInterval(set(page), 10000);
}
But it's not working because browser tries to download pages and at the end, only the last one will be displayed. Function "parse" does not parse pages. How to fix my code?
setInterval will call your set function once every 10 seconds the way you have invoked it. The for loop will have ended before that time, and the page's value at that time will be:
"http://www.*****/*****/3333/*****/";
So after 10 seconds you will only see that page displayed.
Try use setTimeout combine with recursive call.
const MAX=100;
setPage(num){
parse()
if(num<MAX)
setTimeout(setPage(num+1), 10000);
}
When you use setInterval(), you just tells the browser to carry out set() function after 10 seconds, and because all the setInterval() are been called in a very short period of time in that for loop, they will carry out the task together as well, then set will be carried out thrice, first with "1111" then "2222" and "3333".
It would seems like it only run the last one with "3333".
I suggest you use setInterval() only once, while the page variable will be created with a counter.
var counter=0
function count(){
page="http://www.*****/*****/"+numbers[counter]+"/*****/";
set(page);
counter+=1;
if(counter>=numbers.length){
counter=0;
}
}
setInterval(count(), 10000);
It is due to Scopes and Closures in JS. The solution for the problem is to create IIFE(Immediately Invoked Function Expression) inside loop!
for (var i=1; i<=5; i++) {
page="http://www.*****/*****/"+numbers[j]+"/*****/";
(function(j){
setTimeout( set(page), 10000 );
})( i );
}
If you have time, refer about Closures in JS!

Javascript - How to run part of the code only after the page refreshes?

Important: Even though this could probably be done with php (I'm using WooCommerce on Wordpress), I want this script to run only on my browser. That's why I want to do it in Javascript. Hence, I'm using Custom Javascript for Websites to load my script from my browser.
What my script should do: Check if the data of a specific element has been changed.
Logic: Step 1) Get and locally remember specific string (order number) of a specific class. Step 2) Refresh the page. Step 3) Again get the specific string (order number) of a specific class. Step 4) If strings do not match, run a function (play an audio).
Problem: After page reloads, the script starts to run again from the beginning. Hence, it results in overriding the stored string. As a result, stored and newly fetched string are always equal.
Question: How do I make the script to run the 3rd step only after refresh so that the stored data doesn't override itself?
Current code:
var OrderIdOld = document.getElementsByClassName("row-title"); // Select every single element with ClassName "row-title"
var x = (OrderIdOld[0].innerText); // Get the string of the first element of the class "row-title"
var compareOld = x.slice(-1); // Get the last element of the string (since it will be a number, we can change the string into a number easily later)
localStorage.setItem("compareOld", compareOld); // Store this element in local storage, so that it can be used after page reloads.
setInterval ("window.location.reload()", 30000); // Reload page every 30 secs.
var remembered = localStorage.getItem("compareOld"); // Assign stored element to a new var.
var n = compareOld.valueOf(); // Turn stored element into a number (for easy comparison later).
var OrderIdNew = document.getElementsByClassName("row-title"); // Select every single element with ClassName "row-title"
var y = (OrderIdNew[0].innerText); // Get the string of the first element of the class "row-title"
var compareNew = y.slice(-1); // Get the last element of the string (since it will be a number, we can change the string into a number easily later)
var m = compareNew.valueOf(); // Turn fetched element into a number (for easy comparison later).
function beep() {
var snd = new Audio("data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=");
snd.play();
} // Function that will play the sound.
if (n!=m) {
beep();
} // Run function if two numbers are not equal.
Additional: I have gathered the parts of the code from various Questions on stackoverflow. Meaning, I have been searching about this topic for the past week. This is my first questions ever. Hopefully I formatted the question so that it easy to understand.
EDIT: The issue has been solved. I used the idea of only running the first step of function on the first load of page. This post helped me to get functionality working https://stackoverflow.com/a/22334768/7929506
The working code looks like this:
function beep() {
window.open('https://www.youtube.com/watch?v=EQ3zPIj2O5k','_blank');
}
if (sessionStorage.getItem("visit") == null) {
var OrderIdOld = document.getElementsByClassName("row-title")[0].innerText.slice(-1).valueOf();
sessionStorage.setItem("OrderIdOld", OrderIdOld);
sessionStorage.setItem("visit", new Date());
setTimeout("window.location.reload()", 10000);
}
else {
var OrderIdNew = document.getElementsByClassName("row-title")[0].innerText.slice(-1).valueOf();
var x = sessionStorage.getItem("OrderIdOld");
if (x==OrderIdNew) {
setTimeout("window.location.reload()", 10000);
}
else {
beep();
var x = sessionStorage.getItem("OrderIdOld");
sessionStorage.removeItem("OrderIdOld");
sessionStorage.removeItem("visit");
setTimeout("window.location.reload()", 10000);
}
}
When you refresh the page first time, you can simply append a flag variable to URL to identify weather its a refresh or a first time load. Based on that, you can pass a localized variable to script and if that is set then you need to refresh else not.

Writing Multiple into the same ID on HTML

Someone know if after I displays an HTML page I can access a specific ID (getElementById), and change it a value several times?
I want to present a client-side some string and change it several times according the progress of the program, but I can not, it writes to me only recently.
For example:
<script type="text/javascript">
function foo(){
for(var i = 0; i<10000; i++){
document.getElementById('myTag').innerHTML = i;
}
}
</script>
In this case, I do not see the numbers run. I see only the last one.
If I put alert inside the loop - the value is changed.
As i understand your question you want a countup from 0 to 10000 ?
and you want to see the progression on screen ? you could do something like that :
http://jsfiddle.net/camus/ayJFM/
var interval = 500;//milliseconds
var foo = (function () {
var i = 0;
var func = function () {
if (i < 10000) {
document.getElementById("myTag").innerHTML = i;
i += 1;
setTimeout(func, interval);
}
};
return func;
})();
setTimeout(foo, interval);
You're almost there. The only thing you're doing wrong is replacing the innerHTML content instead of adding to it. Change this:
document.getElementById('myTag').innerHTML = i;
to this:
document.getElementById('myTag').innerHTML += i;
Additional/alternative answer:
Wait. I've just reread your question and realized that there is another way of interpreting it. The way you ask it is quite vague so I'm leaving the above answer as is.
The reason you don't see "running numbers" as you process the for loop is because you misunderstand how javascript works in the browser.
The browser's event loop runs something like this:
1. Fetch content
2. Run javscript
3. Render content
then repeat forever
This is how javascript works. So running a simple for loop like you're doing. The browser executes the script until there is nothing else to execute (step 2). Once javascript have finished executing then it will start the render process (step 3). Obviously, by this time the value of i is the final value and therefore you only see the final value.
The browser never interrupts running javascript to render/update the page. So, how do people implement countdown timers etc? They do it by scheduling a piece of javascript to execute in the next iteration of the event loop. That is to say, the let the browser enter step 3 and at the appropriate moment as the browser enters step 2 again they run the script they want.
Javascript basically provides two ways to do this: setTimeout and setInterval.
How setTimeout works is this:
step 1. nothing to do
step 2. setTimeout schedules a piece of javascript to run at a later time
Note that the javascript does not execute yet until setTimeout
expires.
step 3. let the browser update the page
many, many loops of steps 1-3
step 2 (some time later).
setTimeout expires and the piece of javascript executes
step 3. let the browser update the page
So, the get the effect you want, you need to do it like this:
function foo(){
var i = 0;
var update = function(){
document.getElementById('myTag').innerHTML = i;
i++;
if (i<10000) {
setTimeout(update,100);
}
};
update();
}

Javascript Function Stops Safari from Any Other Actions

I am using a Javascript function to animate counting a number up. Whenever that function runs Safari doesn't allow any other Javascript to run on the page, including actions associated with the navigation.
Here is the code:
function animateCountUp(containerSpan){
//We pull the max number from the data-number attribute on the container span.
var maxNumber = containerSpan.attr('data-number');
maxNumber = Number(maxNumber);
//Add active class at start and remove at the end. This way we don't run it again while it's already running.
//This was required for IE7 and IE8.
containerSpan.addClass('active');
var currentNumber = 0;
var i = setInterval(function(){
if(currentNumber <= maxNumber){
containerSpan.text(currentNumber);
currentNumber++;
}
else{
clearInterval();
containerSpan.removeClass('active');
}
}, 1);
}
Any feedback would be much appreciated. Thanks.
I see multiple issues:
Is containerSpan a jQuery object?
You are never stopping the interval because you aren't passing the interval ID to clearInterval like clearInterval(i).
Your interval time is set to 1ms. That's basically going to use max CPU and go way faster than can visually be seen.
If containerSpan is a jQuery object, I would try this:
function animateCountUp(containerSpan){
//We pull the max number from the data-number attribute on the container span.
var maxNumber = containerSpan.data('number');
//Add active class at start and remove at the end. This way we don't run it again while it's already running.
//This was required for IE7 and IE8.
containerSpan.addClass('active');
var currentNumber = 0;
var timer = setInterval(function(){
if(currentNumber <= maxNumber){
containerSpan.text(currentNumber);
currentNumber++;
} else {
clearInterval(timer);
containerSpan.removeClass('active');
}
}, 50);
}
Beyond this, you need to check your error console or debug console to see what javascript errors are being reported. That should always be the very first thing you look at when scripts aren't running as expected.
is containerSpan a jquery object( i.e. $('nameOf the object')) because it looks like you're using jquery methods but i dont see any jquery objects for them to be used on
try right clicking and using inspect element to see if there are any errors in your console log

Categories