Element changed only once in JavaScript function - javascript

I am trying to make an element 'vibrate' using JavaScript upon clicking it by repetitively changing the value of document.getElementById("ElementID").style.left. I change it a number of times in a particular function, but instead of moving each time I change it, it only moves at the end of the function i.e. the last time I make the change. Here is the HTML code:
<html>
<body>
<script>
function changePosition() {
if (document.getElementById("ElementID").style.left == "50%") {
document.getElementById("ElementID").style.left = "52%";
} else {
document.getElementById("ElementID").style.left = "50%";
}
}
function vibrate() {
changePosition();
setTimeout(changePosition, 50);
setTimeout(changePosition, 50);
setTimeout(changePosition, 50);
setTimeout(changePosition, 50);
}
</script>
<button id="ElementID" type="button" style="position:absolute; top:50%; left:50%;" onclick="vibrate()">Vibrate Me</button>
</body>
</html>
At the end I only see the position of the button as it should have been but I can't see the transition during the change. What am I doing wrong?

It seems that all timeouts will execute at the same time. Try changing to this
setTimeout(changePosition,100);
setTimeout(changePosition,200);
setTimeout(changePosition,300);
setTimeout(changePosition,400);
or
for (var i = 1; i < 5; i++) {
setTimeout(changePosition,100*i);
}

Heres an example using setInterval rather than timeout. Mess with the numbers and you should be able to get your desired result
http://jsbin.com/oSIXayun/4/

HTML:
<button id="ElementID" type="button" style="position:absolute; top:50%; left:50%;">Vibrate Me</button>
JS:
function changePosition() {
if (document.getElementById("ElementID").style.left=="50%") {
document.getElementById("ElementID").style.left="52%";
}
else {document.getElementById("ElementID").style.left="50%";}
}
function vibrate() {
changePosition();
setTimeout(changePosition,50);
setTimeout(changePosition,100);
setTimeout(changePosition,150);
setTimeout(changePosition,200);
}
document.getElementById("ElementID").onclick = vibrate;
:)

All the setTimeout calls within vibrate() are made at the same time. You can address this by calling changePosition() based on the number of vibrations you require and repeating the function using setTimeout.
(function () {
var vibrating = 0;
function changePosition() {
if (document.getElementById("ElementID").style.left == "50%") {
document.getElementById("ElementID").style.left = "52%";
} else {
document.getElementById("ElementID").style.left = "50%";
}
if (vibrating != 0) {
vibrating--;
var t = setTimeout(changePosition,50);
}
}
function vibrate() {
vibrating = 4;
changePosition();
}
document.getElementById('ElementID').onclick = vibrate;
})();

Related

JavaScript Timeout reset mechanism

What I want:
There are two pictures that are being switched/swapped every three seconds.
I want to make it so that when the button is clicked, the picture switches and the auto-swap resets. So if the button is clicked, the image swaps and three seconds later, it will auto-swap, until the button is clicked again in which the cycle will repeat.
What I have right now
Currently, the problem is that: when the button is clicked, it messes up the timing of the auto-switches.
Edit:
Please don't create a new code base. Just modify mines. The code doesn't have to be an expert super concise level. I'm only three weeks into JavaScript (and it's my first programming language). I have to explain to classmates and it wouldn't be nice the code had elements I don't understand. So sorry for the inconvenience.
Right now I just need the button to correctly stop and restart the time.
<html>
<head>
<script>
let reset = setTimeout(change, 3000);
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(reset);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
}
</script>
</head>
<body>
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>
The reason why your timer resets is because you are not clearing the timeout.
you need to make a reference to the timeout and then use clearTimeout() on it whne you make the fast change. I don't think it is possible or wise to do that inline the way you have it so you code needs to be refactored
let imgSrc1 = 'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgSrc2 = 'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
let imgElement = document.getElementById('picture');
let timeout;
function change() {
if(imgElement.src === imgSrc1) {
imgElement.src = imgSrc2;
} else {
imgElement.src = imgSrc1;
  }
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(change, 3000);
}
You don't even need the second function fastChange. Now you can sent the onClick listener to change() like this
document.getElementById('whatever you want to click').onCLick = change;
Setting and clearing timeouts in multiple places will work, but I prefer using a "main loop" and a variable to count frames.
Here's an example that uses setInterval and resets a timer variable when the button was clicked:
const url1 = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
const url2 = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
function change() {
picture.src = picture.src == url1 ? url2 : url1;
}
var timer = 0;
setInterval(function() {
timer++;
time.textContent = timer;
if (timer === 30) fastChange();
}, 100);
function fastChange() {
change();
timer = 0;
}
picture.src = url1;
swap.onclick = fastChange;
#picture {
height: 70vh
}
<button id="swap">SWAP</button> <span id="time"></span><br>
<img id="picture">
You can do this by calling setTimeout and updating the index as necessary. Just be sure to store the most recent timeout id so that it can be cancelled on reset using clearTimeout.
// store the reference to the <img> that contains the picture
const pic = document.getElementById('picture')
// store a list (array) of the two picture urls
const sources = [
'https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350',
'https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350'
]
// used to store a reference to the interval timer you created.
var lastTimer
// a starting index of the list (i.e. which image we are up to right now)
var index = 1
// this functions swaps the image and sets a timer
function startRotation() {
// update the index to the next one (goes 0-1-0-1->etc)
index = 1 - index
// sets the .src of the image element
pic.src = sources[index]
// starts a 3 second timer to call this same function again
// but also stores a reference to the timer so that it can be cancelled
lastTimer = setTimeout(startRotation, 3000)
}
// this functions resets the timer and restarts the process
function reset() {
// stop the current timer if there is one
if(lastTimer){
clearTimeout(lastTimer)
}
// restart the process
startRotation()
}
// start the swapping process on start
startRotation()
<input type="button" onclick="reset();">
<img id="picture">
NOT HOW YOU CLEARTIMEOUT:
<html>
<head>
<script>
var i;
function change() {
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
function fastChange() {
clearTimeout(i);
if(document.getElementById("picture").src == "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350") {
document.getElementById("picture").src = "https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&h=350";
}
else {
document.getElementById("picture").src = "https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350";
}
i = setTimeout(change, 3000);
}
</script>
</head>
<body onload="setTimeout(change, 3000)">
<input type="button" onclick="fastChange();">
<img src="https://images.pexels.com/photos/248797/pexels-photo-248797.jpeg?auto=compress&cs=tinysrgb&h=350" id="picture">
</body>
</html>

Stop function after certain number of clicks on a certain element

OK so I am making a reaction tester, and I have a function that makes shapes appear on screen, So what I want is some sort of function were after 5 clicks on a certain element it will end a function. Is there a way of doing that? sorry if its a dumb question, its because I am new to the whole coding...
Here you go
var clickHandler = (function (e) {
var count = 0;
return function () {
count += 1;
if (count > 5) {
return;
}
// do other stuff here
}
}());
aDiv.addEventListener('click', clickHandler, false);
You Can use static variable to count how many times the object has been clicked.
and here is how you can create static variable in javascript.
You can unbind the click event once the counter reaches 5. See the example below
function test(sender) {
sender.dataset.clicked++;
console.log("I've been clicked", sender.dataset.clicked);
if (+sender.dataset.clicked === 5) {
// unbind the event
sender.onclick = null;
}
return;
}
<div onclick="test(this);" data-clicked="0">click me</div>
You may use global variable which may remain counting on click function
<script>
var globalvar = 0;
onclickfunct()
{
globalvar += 1;
if(globalvar == 5)
{
//do my work
}
else
{
//give alert
}
}
</script>

JS function that stops another JS function

I have two JS functions: a load() function that displays a progress bar and a kill () function that stops the execution of the load once the page is loaded.
Now when another page is loaded the progress bar is not displayed, knowing that the load function is called on every page.
Any hints on where the problem might be and if there is a way to fix it.
Here is my code:
<script type="text/javascript">
var count=0;
function load(i) {
j = parseInt(i);
document.getElementById("progressBar").style.display = "block";
count=count+1;
if (document.all) {
document.all.btn1.value=count+'%';
document.all.progressbar.pic1.width=2*count;
}
else {
document.getElementById("pic1").width=2*count;
document.getElementById("bar").width=count+'%';
}
if (count<100) {
setTimeout('load(j)',j);
}
if(count==100) {
document.getElementById("progressBar").style.display = "none";
count=0;
}
}
function kill(){
if (document.applets[0].isActive()) {
document.getElementById("progressBar").style.visibility = "hidden";
}
}
</script>
Thank you in advance !
In load() you're changing display to block, but in kill() you set visibility to hidden; you should set display to none instead, so it can properly be set to block again next time. Read about visibility.
Optimized code:
<script type="text/javascript">
var count = 0,
win = window,
doc = document,
progressBar = doc.getElementById("progressBar"),
t, j;
function load(i) {
j = parseInt(i);
progressBar.style.display = "block";
count++;
// no actual need to check if doc.all is available
// just select through id
doc.getElementById("pic1").style.width = 2*count;
doc.getElementById("bar").style.width = count+'%';
if (count < 100) {
t = win.setTimeout('load(j)',j);
} else {
progressBar.style.display = "none";
win.clearTimeout(t);
count = 0;
}
}
function kill(){
if (doc.applets[0].isActive()) {
progressBar.style.display = "none";
}
}
</script>
If you assign setTimeout to a variable, you can use clearTimeout on it to stop it.
E.g.
set the timeout with
t = setTimeout('load(j)',j);
then stop it with
clearTimeout(t); Let me know if that helps, and makes sense :)

Pause Javascript for a few seconds on click

Ok i know this has to be a topic discussed earlier, but all the answers I found were a little complicated considering I'm new and still in the process of learning javascript.
I have the following code in the head section of my html
<script>
function timedText() {
setTimeout(function(){displayResult()},3000);
setTimeout(function(){displayResult1()},7000);
setTimeout(function(){displayResult2()},15000);
setTimeout(function(){timedText()},18000);
}
</script>
<script>
function change() {
setTimeout(function(){timedText()},1000);
}
</script>
<script>
function displayResult() {
document.getElementById("adimg_holder").style.bottom="0px";
document.getElementById("button1").style.backgroundPosition="bottom";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult1() {
document.getElementById("adimg_holder").style.bottom="370px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="bottom";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult2() {
document.getElementById("adimg_holder").style.bottom="739px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="bottom";
}
</script>
and the following html
<body onload="change()">
<div class="banner_area">
<div class="banner_wrapper">
<img src="images/image_holder.png" />
<div id="ad_holder">
<div id="adimg_holder">
<img class="ad_images" src="images/recruitment_banners.png" />
<img class="ad_images" src="images/training_banners.png" />
<img class="ad_images" src="images/staffing_banner.png" />
</div>
</div>
<div id="ad_buttons">
<div id="button1" style="background-image:url(images/buttonfirst.png);background-position:bottom;width:259px;height:41px" onclick="displayResult()"></div>
<div id="button2" style="background-image:url(images/buttonsecond.png);width:259px;height:41px" onclick="displayResult1()"></div>
<div id="button3" style="background-image:url(images/buttonthird.png);width:259px;height:41px" onclick="displayResult2()"></div>
</div>
</div>
</div>
So the buttons toggle different positions, and the script cycles through the positions at time intervals
Now what I'm trying to achieve is that when the positions are being cycled through, if I click on one of the button, it jumps to the related position and stays that way for a while (say a few seconds) and then continue with the loop.
Hope I've made my motive easy to understand.
Here is how you can achieve this behavior: http://jsfiddle.net/PcZsT/12/
Here is the JavaScript:
function timedText() {
setTimeout(function() {
displayResult();
},2000);
setTimeout(function() {
displayResult1();
},6000);
setTimeout(function() {
displayResult2();
},14000);
setTimeout(function() {
timedText();
},15000);
}
(function change() {
setTimeout(function() {
timedText();
},1000);
}());
var locked = false;
function button1Handler() {
moveTop();
lockFor(3);
}
function button2Handler() {
moveBottom();
lockFor(3);
}
function lockFor(seconds) {
locked = true;
setTimeout(function () {
locked = false;
}, seconds * 1000);
}
function displayResult() {
if (locked) return;
moveTop();
}
function moveTop() {
document.getElementById("adimg_holder").style.bottom="0px";
document.getElementById("button1").style.backgroundPosition="bottom";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult1() {
if (locked) return;
moveMiddle();
}
function moveMiddle() {
document.getElementById("adimg_holder").style.bottom="370px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="bottom";
document.getElementById("button3").style.backgroundPosition="top";
}
function displayResult2() {
if (locked) return;
moveBottom();
}
function moveBottom() {
document.getElementById("adimg_holder").style.bottom="739px";
document.getElementById("button1").style.backgroundPosition="top";
document.getElementById("button2").style.backgroundPosition="top";
document.getElementById("button3").style.backgroundPosition="bottom";
}
The functions above are the click handlers of respectively button1 and button2.
I've also changed the change function to бe IIFE (Immediately Invoked Function Expression) but it's not necessary, you don't have to do it because you want to be invoked onload.
you don't need so much code : just make one displayResult function that will call itself over and over :
var scrollParam = { scrollPos : 0, // current pos
scrollIncr : 370, // incr in px each call
loopScrollAfter : 700 // set scrollPos to >0 if above that number
delay : 3000, // std scroll delay
whichIsOnTop : 0, // index of the topmost item (button)
pauseDelay : 1000, // added delay if someone clicks
pauseRequired : 0 }; // current required click delay
var mainItem = document.getElementById("adimg_holder");
function displayResult()
{
mainItem.style.bottom=scrollParam.scrollPos +"px";
scrollParam.scrollPos += scrollParam.scrollIncr;
if (scrollParam.scrollPos>scrollParam.loopScrollAfter) scrollParam.scrollPos=0;
setBackgroundPosition("button1",0);
setBackgroundPosition("button2",1);
setBackgroundPosition("button3",2);
scrollParam.whichIsOnTop = (scrollParam.whichIsOnTop + 1) % 3;
// now setup the next call, taking into account if a pause is required
var requiredDelay = scrollParam.delay;
if (scrollParam.pauseRequired >0) {
requiredDelay += scrollParam.pauseRequired;
scrollParam.pauseRequired=0;
}
setTimeout(displayResult, requiredDelay);
}
var setBackgroundPosition(itemName, index ) {
document.getElementById(itemName).style.backgroundPosition=topOrBottom(index );
};
// returns "top" for the right index (==scrollParam.whichIsOnTop) and "bottom" for the others
var topOrBottom(thisIndex) { return (thisIndex == scrollParam.whichIsOnTop) ? "top" : "bottom"; };
// in the button click handler you should use :
scrollParam.pauseRequired += scrollParam.pauseDelay;
// to launch the scroll, just call :
displayResult(); // in the loaded() event handler for example.
Rq : you can change easily the parameters to have a smoother scrolling if you like.
you can make use of the setTimeout timing function itself.
write a function as:
function calldesiredFunctionafterPause (functionTobeCalled){
setTimeout(function(){functionTobeCalled,1000}) //increase the millisec as needed
}
and on the onClick call this function and pass the function name as parameter.
This will make the onclick function to be delayed for the required time

setInterval and clearInterval not working as expected

I have this function which acts as a loading box using setInterval to change the background images which creates a flashing effect.
function loading() {
clearInterval(start);
var i = 0;
function boxes() {
in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
var start = setInterval(function() {
boxes();
}, 350);
}
But even with clearInterval if I click on it more than once the flashing goes out of order. I tried removing the boxes, hiding them but I can't seem to get the 'buffer' cleared? Any ideas?
The reason why it keeps flashing is because every time loading gets called it creates a new variable start, so clearInterval is actually doing nothing. You also shouldn't have the boxes function within loading because it is doing the same thing, creating a new boxes function every time loading is called. This will add a lot of lag the longer the script executes.
var i = 0;
var start;
function loading() {
clearInterval(start);
start = setInterval(function() {
boxes();
}, 350);
}
function boxes() {
var in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
Function declarations get "hoisted" to the top of their scope, this is what is messing the execution order. Check this: http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
The reason is every time you call loading it creates a new Interval or new var start. So if you click it twice, then you have two things manipulating the same data. So you need to have the var start outside of the function and the clearInterval inside. So every time you call loading it clears the interval and creates a new one.
var i = 0;
var start;
function loading() {
clearInterval(start);
start = setInterval(boxes, 350);
}
function boxes() {
in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
maybe you should take a look at this Jquery Plugin , it seems to manage intervals very well .
Jquery Timers Plugin

Categories

Resources