Simple Javascript Image Rotation Not Properly Looping - javascript

This is a simple rotation script that is not working. It has four alerts: currentImage, 1, 2, and 3. In FF it goes through four alerts and stops. In Chrome, it goes through five. The image only changes once in both browsers.
function rotateImages(currentImage, id) {
var dir = "/images/";
var a = new Array("coolspider1.jpg", "coolspider2.jpg", "coolspider3.jpg");
var b = document.getElementById(id);
if(currentImage >= a.length){
currentImage=0;}
//loop stops here in ff
alert(a[currentImage]);
//loop stops here in chrome
b.src = dir + a[currentImage];
alert(1);
currentImage++;
alert(2);
rotator = window.setTimeout("rotateImages(" + currentImage + "," + id + ")",500);
alert(3);
}

There's a lot of issues here:
You are accessing the DOM too much with getElementById each time. Instead pass the element.
You are creating the same array each time. var a = new Array(...) can be created once.
You are never assigning to currentImage
You are using setTimeout weirdly, instead of a simple loop, for(i;etc..) setTimeout(func, 500 + i*500, params...)
You are using alert for something... not sure
Replace:
window.setTimeout("rotateImages(" + currentImage + "," + id + ")",500);
with:
window.setTimeout(rotateImages,500, currentImage, id);
setTimeout takes optional parameters of the... well, parameters.

Related

What is the proper syntax for using variables inside of "url(' ')" when trying to change the background of an image? Javascript

I'm trying to consistently cycle what my background image is using an Array variable, but I cannot seem to figure out how to properly write the variable into the url section.
window.setInterval (function borderChange() {
var backgrounds = [
"../pictures/background1.png",
"../pictures/background2.png",
"../pictures/background3.png",
"../pictures/background4.png"
];
var counter = 0;
document.getElementById("borderOne").style.backgroundImage = "url('"+backgrounds[counter]+"')";
counter++;
if (counter == 4) {
counter = 0;
}
}, 5000)
I've tried writing the url line in the following ways (and many more that gave me errors in VS) with no luck:
"url('"+backgrounds[counter]+"')";
"url('" + backgrounds[counter] + "')";
"url('' + "+backgrounds[counter]+")";
"url(";backgrounds[counter];")";
"url("+backgrounds[counter]+")";

Prevent function from invoking until flag get set to true

I have created pretty easy gallery. The elements gets their transform position increased or decreased on click using
function pushIt(max, target, index, count) {
if (count == max ) {
target[index -1].addEventListener("transitionend",turnOf,false);
return;
}
var tmp = target[index];
var matrix = window.getComputedStyle(tmp).getPropertyValue("transform");
var translate_left = matrix.split(",")[4];
var translate_top = matrix.split(",")[5].split(")")[0]-215;
tmp.style.transform = "translate3d(" + translate_left + "px," + translate_top + "px,0)";
setTimeout(function(){
pushIt( max, target, index + 1, count + 1 );
},50)
}
function turnOf(){
running = false;
this.removeEventListener(turnOf);
}
Everything is working fine , but the problem is , when i click xxx time rly fast , it gets destroyed and does unwanted behavior. I am using flag, so the function can be called only when "running" is false , which i return back to false when the transition of the last element that should be moved is over. It works on the first few clicks , but fast clicking ruins it and break whole script.
Live demo ( click rly fast xxx times to see the behavior )
What could cause this? The flag is only set only when the transition ends, so why the function gets invoked ? Is there a way how to fix it , or shoud i use brute force ( promises ) for this?
This seems to be your problem:
function turnOf(){
running = false;
//this.removeEventListener(turnOf);
this.removeEventListener("transitionend", turnOf);
}

JavaScript Automated Clicking

So, here's my issue.
I need to write a script to be run in the console (or via Greasemonkey) to automate clicking of certain links to check their output.
Each time one of these links is clicked, they essentially generate an image in a flash container to the left. The goal here is to be able to automate this so that the QC technicians do not have to click each of these thumbnails themselves.
Needless to say, there needs to be a delay between each "click" event and the next so that the user can view the large image and make sure it is okay.
Here is my script thus far:
function pausecomp(ms) {
ms = ms + new Date().getTime();
while (new Date() < ms){}
}
var itemlist, totalnumber, i;
itemlist = document.getElementsByClassName("image");
totalnumber = parseInt(document.getElementById("quickNavImage").childNodes[3].firstChild.firstChild.nodeValue.replace(/[0-9]* of /, ""));
for(i = 0; i < totalnumber; i = i + 1) {
console.log(i);
itemlist[i].childNodes[1].click();
pausecomp(3000);
}
Now, totalnumber gets me the total number of thumbnails, obviously, and then itemlist is a list of get-able elements so I can access the link itself.
If I run itemlist[0].childNodes[1].click() it works just fine. Same with 1, 2, 3, etc. However, in the loop, it does nothing and it simply crashes both Firefox and IE. I don't need cross-browser capability, but I'm confused.
There is a built-in JS function "setInterval(afunction, interval)" that keeps executing a given function every "interval" miliseconds (1000 = 1s).
This fiddle shows how to use setTimeout to work through an array. Here is the code:
var my_array = ["a", "b", "c", "d"];
function step(index) {
console.log("value of my_array at " + index + ":", my_array[index]);
if (index < my_array.length - 1)
setTimeout(step, 3000, index + 1);
}
setTimeout(step, 3000, 0);
Every 3 seconds, you'll see on the console something like:
value of my_array at x: v
where x is the index in the array and v is the corresponding value.
The problem with your code is that your pausecomp loop is a form of busy waiting. Let's suppose you have 10 items to go through. Your code will click an item, spin for 3 seconds, click an item, spin for 3 seconds, etc. All your clicks are doing is queuing events to be dispatched. However, these events are not dispatched until your code finishes executing. It finishes executing after all the clicks are queued and (roughly) 30 seconds (in this hypothetical scenario) have elapsed. If the number of elements is greater that's even worse.
Using setTimeout like above allows the JavaScript virtual machine to regain control and allows dispatching events. The documentation on setTimeout is available here.
People were correct with SetInterval.
For the record, here's the completed code:
/*global console, document, clearInterval, setInterval*/
var itemlist, totalnumber, i, counter;
i = 0;
function findmepeterpan() {
"use strict";
console.log("Currently viewing " + (i + 1));
itemlist[i].scrollIntoView(true);
document.getElementById("headline").scrollIntoView(true);
itemlist[i].style.borderColor = "red";
itemlist[i].style.borderWidth = "thick";
itemlist[i].childNodes[1].click();
i = i + 1;
if (i === totalnumber) {
clearInterval(counter);
console.log("And we're done! Hope you enjoyed it!");
}
}
function keepitup() {
"use strict";
if (i !== 0) {
itemlist[i - 1].style.borderColor = "transparent";
itemlist[i - 1].style.borderWidth = "medium";
}
findmepeterpan();
}
itemlist = document.getElementsByClassName("image");
totalnumber = parseInt(document.getElementById("quickNavImage").childNodes[3].firstChild.firstChild.nodeValue.replace(/[0-9]* of /, ""), 10);
counter = setInterval(keepitup, 1500);

setInterval() change image

The goal: When the page is loaded, display the image andy_black.jpg. After two seconds, change the image source, and the thus image in the browser, to a second image called andy_white.jpg. This will change back and forth every 2 seconds.
I checked out this article:
SetInterval function calls
(I searched other as well, with the tags [javascript] [function] and the word "setinterval", but most were using jQuery and my intention here is not to use any jQuery, it's an experiment in JavaScript after all).
which was quite helpful for before I had read it my code was much longer and the function was not called in the setInterval() function.
So here's some code:
Suggestions?
var i = 1;
function change_pic() {
i + 1;
if (i == 5) {
i = 1;
}
//I suspect the computer will read i as 5 for some
//tiny amount of time before reverting back to 1
//which I suspect could cause a further problem, but
//is it the source of the current issue?
if (i == 1 || i == 2) {
document.getElementById('img_to_flip').src = "https://cdns-images.dzcdn.net/images/artist/5d9e44027cc266260d7bd932d98f739d/500x500.jpg";
} else {
document.getElementById('img_to_flip').src = "https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg";
}
}
var pic_src = setInterval(change_pic, 2000);
<img id="img_to_flip" src="https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg" height="100" width="100" />
You forget to actually reassign the new value to i.
Either use:
i = i + 1;
or
++i;
Also, why count to five when you only have two states? A common paradigm to have an auto-resetting counter is to use modulo arithmetic:
i = (i + 1) % 2;
which guarantees that i will only ever have values of 0 or 1.
FWIW, here's an alternate way of writing the entire feature that'll work for any number of images - just populate the pics array:
(function() { // function expression closure to contain variables
var i = 0;
var pics = ["https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg", "https://cdns-images.dzcdn.net/images/artist/5d9e44027cc266260d7bd932d98f739d/500x500.jpg"];
var el = document.getElementById('img_to_flip'); // el doesn't change
function toggle() {
el.src = pics[i]; // set the image
i = (i + 1) % pics.length; // update the counter
}
setInterval(toggle, 2000);
})(); // invoke the function expression
<img id="img_to_flip" src="https://media.s-bol.com/q7R3B8QVrAj2/550x549.jpg" height="100" width="100" />
If you want to avoid the delay in first time setInterval call the function before the setInterval as shown in the top answer:
(function() { // function expression closure to contain variables
var i = 0;
var pics = [ "andy_white.jpg", "andy_black.jpg" ];
var el = document.getElementById('img_to_flip');
function toggle() {
el.src = pics[i]; // set the image
i = (i + 1) % pics.length; // update the counter
}
toggle()
setInterval(toggle, 2000);
})(); // invoke the function expression

Javascript character limit counter function for text input

I've made a counter with javascript that shows a user how characters are remaining (from a set limit) for some text input or text area. Here's the code:
<script type="text/javascript">
function CountRemaining()
{
var limit = 1000;
var count = document.getElementById('press-form-body').value.length;
document.getElementById('counter').innerHTML = ((limit-count) + " characters left");
var timer = setTimeout("CountRemaining()",50);
}
</script>
My abomination above works fine but my problem is that I need to use this multiple times and making a separate function for every time I need it would be impractical to say the least.
I tried this and it didn't work:
<script type="text/javascript">
function CountRemaining(string, targetcounter, limit)
{
var count = document.getElementById(string).value.length;
document.getElementById(targetcounter).innerHTML = ((limit-count) + " characters left");
var timer = setTimeout("CountRemaining()",50);
}
I then figured I put the wrong statement for the timer so I changed it to this but still didn't work:
var timer = setTimeout("CountRemaining(string, targetcounter, limit)",50);
I'm lost. Any help would be highly appreciated. Thank you!
I think a better idea would be to use the "onchange" event for those types of elements.
Basically as soon as the text area / text input loses focus and is changed, you can bind a function to count how many characters are left.
document.getElementById('press-form-body').onchange = function() {
// your stuff (double check this to make sure the "this" value is right
// use this as an example
document.getElementById(targetcounter).innerHTML = this.value.length - 1000
}
Another solution would be to use the "key" events to listen to any keypress in the inputs.
document.getElementById('press-form-body').onkeypress = function() {
// your stuff (double check this to make sure the "this" value is right
// use this as an example
document.getElementById(targetcounter).innerHTML = this.value.length - 1000
}
function limittxt()
{
var tval = document.getElementById('press-form-body').value;
tlength = tval.length;
set = 100;
remain = parseInt(set - tlength);
document.getElementById('counter').innerHTML = remain + " characters left";
if (remain <= 0) {
document.getElementById('press-form-body').value = tval.substring(0, tlength - Math.abs(remain)))
}
}
An call this function in the input element like the following :
<input type='text' onkeypress='limittxt()' onkeyup='limittxt()' onkeydown='limittxt()'>
I suppose the error is with following line:
var timer = setTimeout("CountRemaining(string, targetcounter, limit)",50);
Here i think it should come like:
var str = "CountRemaining(" + string + "," + targetcounter + "," + limit + ")";
var timer = setTimeout(str,50);
If you want to proceed along the lines of using the timer to run the function at regular intervals, then you would need code similar to the following (hat-tip to #Sameera Thilakasiri for the inspiration):
function CountRemaining(string, targetcounter, limit){
var count = document.getElementById(string).value.length;
document.getElementById(targetcounter).innerHTML = ((limit-count) + " characters left");
}
setInterval(function() {
// call the function for each of the inputs on the page you need a counter for
CountRemaining('press-form-body', 'counter', 1000);
// etc
}, 50);
However, I believe #amchang87's approach is better overall, so I recommend you go with that if possible.
Tracking the number of characters left is always a little difficult. A good event to use is keyup or keypress, but that doesn't cover text that is dragged and dropped into the element, so people end up using a timer.
If you have many elements to monitor, consider putting them into an array, then call the timer at each interval and check all of the elements. Be careful with performance though, running the function every 50 ms may sap quite a bit of browser performance so try to keep the processing to an absolute minimum.
That means caching whatever you can and keep the logic simple.
Edit
The run and stop methods below could be used to start the timer when particular elements get focus, then stop it when they lose focus. That way you aren't hogging resources when not required.
/Edit
var keyCountCheck = (function() {
var elementArray, timerRef;
return {
// Initialise once
init: function() {
var input, inputs;
// Initialise elementArray if hasn't been done already
// If adding and removing elements, create new aray
// instead each time.
if (!elementArray) {
elementArray = [];
inputs = document.getElementsByTagName('input');
for (var i=0, iLen=inputs.length; i<iLen; i++) {
input = inputs[i];
if (input.type == 'text') {
elementArray.push(input);
}
}
}
timerRef = window.setInterval(keyCountCheck.run, 50);
},
// Run timer
run: function() {
// If setInterval not running, start it
if (!timerRef) {
keyCountCheck.init();
}
var el;
for (var i=0, iLen=elementArray.length; i<iLen; i++) {
checkLength(elementArray[i]);
}
},
// In case there is a reason to stop this thing.
stop: function() {
if (timerRef) {
window.clearTimeout(timerRef);
timerRef = null;
}
}
};
}());
window.onload = keyCountCheck.init;
function checkLength(el) {
// Character limit can be set as a data- attribute or
// class or various other ways. This is the simple way
var limit = 10;
var msgEl = document.getElementById(el.id + '_limitMsg');
if (msgEl) {
msgEl.innerHTML = (limit - el.value.length) + ' characters left. ' + (new Date());
}
}
Some supporting HTML to play with:
<input id="i0" value="1"><span id="i0_limitMsg"></span>
<br>
<input id="i1" value="2"><span id="i1_limitMsg"></span>
<br>
<button onclick="keyCountCheck.stop()">stop</button>
<button onclick="keyCountCheck.run()">run</button>
setInterval(
function CountRemaining(string, targetcounter, limit){
var count = document.getElementById(string).value.length;
document.getElementById(targetcounter).innerHTML = ((limit-count) + " characters left");
},50
);
Tryout this way.
Basic concept of this solution,
var f = function() {function_name(arg1); };
setTimeout(f, msec);

Categories

Resources