I am setting an interval in the global scope so it can be cleared and restarted within functions. However, when I call it from within a function, it seems to be undefined. My understanding (and I've just done a ton of reading) is that Javascript variables defined outside of functions (var this = '' OR var this;) are global and accessible from anywhere else in the code. Every time I check my (allegedly) global variable from within a function, it is inaccessible.
As far as defining my global variable, I have tried a few options and none have worked. I have tried setting the variable but not giving it a value:
var mainTimeout;
I have tried setting it AND giving it an initial value:
var mainTimeout='x';
I have tried setting it as the actual time interval that it will eventually be:
var mainTimeout = setInterval(function(){setTimeClckState('default');}, 15000);
Regardless of which option I choose, I try calling it later from within a function like this:
$(".timeClckControls input[type=button]").click(function(){
if(mainTimeout){clearInterval(mainTimeout)}else{console.log('no timeout var set');};
});
Without fail, I always get console logged "no timeout var set". So it is never being recognized from within the function, even though I defined my variable with global scope. The result of this is that my time interval just stacks and it constantly triggers after the function is triggered a few times. Please help, I am out of ideas!
Full Code:
var mainTimeout = setInterval(function(){setTimeClckState('default');}, 15000);
$(".timeClckControls input[type=button]").click(function(){
if(!($(this).val()=='IN')&&!($(this).val()=='OUT')){
// IF CLEAR BUTTON, SET TIME CLOCK TO DEFAULT
if($(this).val()=="CL"){
setTimeClckState('default');
// IF BUTTON IS 4TH CHARACTER
}else if($('#empIDTxt').val().length==3){
$('#empIDTxt').val($('#empIDTxt').val()+$(this).val());
$('.timeClckControls .btn-primary').prop('disabled',true);
getEmpData();
}else{
$('#empIDTxt').val($('#empIDTxt').val()+$(this).val());
}
}
if(mainTimeout){clearInterval(mainTimeout)}else{console.log('no timeout var set');};
var mainTimeout = setInterval(function(){setTimeClckState('default');}, 15000);
});
function setTimeClckState(state){
switch(state){
case "default":
$('.timeClckControls input[type=text]').val('');
$('.timeClckControls input[type=button]').prop('disabled',false);
$('#statusDiv .alert').removeClass('alert-warning');
$('#statusDiv .alert').removeClass('alert-success');
$('#statusDiv .alert').addClass('alert-secondary');
$('#statusDiv .alert').html(' ');
$('#clockInOutBtn').removeClass('btn-warning');
$('#clockInOutBtn').removeClass('btn-success');
$('#clockInOutBtn').addClass('btn-secondary');
$('#clockInOutBtn').prop('disabled',true);
$('#clockInOutBtn').val('CLK');
$('#clearBtn').removeClass('btn-warning');
$('#clearBtn').removeClass('btn-success');
$('#clearBtn').addClass('btn-secondary');
$('#clearBtn').prop('disabled',true);
break;
case 'clockedIn':
$('#clearBtn').prop('disabled',false);
$('#clockInOutBtn').prop('disabled',false);
$('#clockInOutBtn').removeClass('btn-success');
$('#clockInOutBtn').addClass('btn-warning');
$('#clockInOutBtn').val('OUT');
break;
case 'clockedOut':
$('#clearBtn').prop('disabled',false);
$('#clockInOutBtn').prop('disabled',false);
$('#clockInOutBtn').addClass('btn-success');
$('#clockInOutBtn').removeClass('btn-warning');
$('#clockInOutBtn').val('IN');
break;
}
}
Okay I figured it out. Thanks to #Mischa, helped me realize what was happening. Problem was that I'm resetting the variable from within a function each time. So the variable actually ends up not having global scope. Googled "how to define global variable from within function". Turns out the best way is to set "window.myVar" from inside function. Ended up just making one function to stop and restart the interval:
function stopStartClearInt(){
if(window.mainTimeout){clearInterval(window.mainTimeout)}else{console.log('no timeout var set');};
window.mainTimeout = setInterval(function(){
setTimeClckState('default');
console.log('Interval check');
}, 5000);
}
I can run this from literally anywhere in my script and it will work!
Your code should work fine:
function setTimeClckState(str) {
console.log(str);
}
var mainTimeout = setInterval(function(){setTimeClckState('default');}, 500);
$(".timeClckControls input[type=button]").click(function(){
if(mainTimeout){
clearInterval(mainTimeout)
} else {
/**
* The return value of setInterval is just a unique id you use to pass back to
* clearInterval. It's not a structured object with any additional information,
* nor does it get set to null when you call clearTimeout. So even its cleared
* it will never be falsy
*/
console.log('no timeout var set');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="timeClckControls">
<input type="button" value="click me" />
</div>
Related
I have the following code. Pressing the first button sends the user to a different URL after 10 seconds.
However, I am also trying to get the second button to cancel that redirect if pressed before those 10 seconds. This doesn't seem to work and the URL redirect still occurs.
I have looked online for various solutions and I am unable to get anything to work. I have also tried swapping out setTimeout/clearTimeout with setInterval/clearInterval and other variations of the code.
I would be willing to have the code changed completely or use Jquery instead etc. I have been trying to do this for past couple of days so any help would be greatly appreciated.
If the redirect countdown could also start again from 10 seconds if the first button is pressed again after pressing the second button, that would be also great.
Javascript
<script>
var redirectTime = "10000";
var redirectURL = "https://realmbound.com";
function timedRedirect() {
var timeoutHandle = window.setTimeout("location.href = redirectURL;",redirectTime);
}
function stopTimer() {
clearTimeout(timeoutHandle);
}
</script>
HTML
<button onclick="JavaScript:timedRedirect()">Click me for a timed redirect.</button>
<button onclick="JavaScript:stopTimer()">Stop Timer.</button>
Your timeoutHandle is in scope function, you must delcare it to global scope it in your order to access it on stopTimer().
let redirectTime = "1000";
let redirectURL = "https://realmbound.com";
let timeoutHandle;
function timedRedirect() {
timeoutHandle = window.setTimeout("location.href = redirectURL;",redirectTime);
}
function stopTimer() {
clearTimeout(timeoutHandle);
}
<button onclick="JavaScript:timedRedirect()">Click me for a timed redirect.</button>
<button onclick="JavaScript:stopTimer()">Stop Timer.</button>
The rest of the code is fine.
Your solution is correct, only thing that you missed is to scope timeoutHandle variable as global scope so that stopTimer function can access it.
here is the working fixed version of your solution:
https://jsfiddle.net/8uw7f19k/1/
Hope it helps ;-)
I have this code in JavaScript:
status = document.getElementById('status2');
$('#slider > img').hover(
function() {
stopLoop();
status.innerHTML = "paused";
},
function() {
startSlider();
status.innerHTML = "playing";
}
);
where I look for all the images in my html that have the id slider and when I hover on then I want to add a word (paused or playing) to a span tag that has the id status2. But I don't know why the global variable is not working, the only way that I make it work is putting a local variable inside each funcion like this:
function() {
stopLoop();
var status = document.getElementById('status2');
status.innerHTML = "paused";
},
function() {
startSlider();
var status = document.getElementById('status2');
status.innerHTML = "playing";
}
Can anyone me why?
NOTE: as I said before all works with the local variables but not setting it as a global variable.
Because by the time you run
status = document.getElementById('status2');
DOM was not ready so you get status as undefined and so it wont work further.
So either put the code in ready
$(document).ready(function(){
//code goes here
})
or
Put the script at the end of file.
Do add in a
$(document).ready(function(){
});
This waits to execute the code inside until everything has finished loading. That way it shouldn't return undefined.
ALSO
I couldn't help but noticing that you seem to be trying to give multiple items the same ID.
Don't use IDs for multiple elements. That's not how they are designed to be used, nor do they work that way.If you give multiple elements the same ID and then try and style them with CSS, it'll only style the first one. Use a class. If you use
document.getElementById();
to try and grab multiple elements with the same ID, then the script will ONLY grab the FIRST element with that ID, because, given that it is an ID, it expects only one element. If you want to work with multiple elements, use a class, and then use
document.getElementsByClassName();
this will grab ALL elements with that class. So for example,
say you have four span elements with the class "foo". To grab all these and change the text, do this:
elements=document.getElementsByClassName("foo");
for (i=0; i<elements.length; i++){
elements[i].innerHTML='insert your text here';
}
About global and local variables, a GLOBAL variable is declared this way:
global_variable='foo'
and a local variable is declared this way:
var local_variable='foo'
a Global variable can be declared anywhere in the script and be used anywhere inside the script(and even in other scripts that are attached to the same HTML file ), whereas a Local variable, if declared inside the function, can only be used inside the function, or if you declare it outside the function, it can't be accessed within the function unless you pass the variable to it.
Hope that helps!
I am debugging the weirdest error I ever seen. At this point my code look like this.
var counter = 0;
function setup() {
var count = ++counter;
var test = false;
function getSetter(arg?) {
if (typeof (arg) !== "undefined") {
console.log(["setting",count, arg]);
test = arg;
} else {
console.log(["getting",count, test]);
return test;
}
}
return getSetter;
}
var verticalScrollDisabled = setup();
this is in a closed scope and i have made sure that the variable test is not accessed outside the above code. I can change it to any name with same result. Updated such its clear that its not accessed outside of this scope. And updated with a counter to show its not written over.
Copy pasting result from the console.
["enter scroll area", div.fxs-blade-content, true, "3511>401 || 577>585"] HorizontalScrollBindingHandler.ts:12
["setting", 1,true] HorizontalScrollBindingHandler.ts:132
disable vert HorizontalScrollBindingHandler.ts:72
n.Event {originalEvent: WheelEvent, type: "mousewheel", isDefaultPrevented: function, timeStamp: 1422128039040, jQuery21104183536011260003: true…} HorizontalScrollBindingHandler.ts:15
["getting", 1,false] HorizontalScrollBindingHandler.ts:15
["getting", 1, false] HorizontalScrollBindingHandler.ts:75
[false, false]
Issue
As commented, my problem is that as seen in the trace. the variable get set to true, but when its being accessed again its false. I cant get why that can happen.
and the handler attached to mousescroll event.
var scrollHorizontally =(e) => {
// console.log([verticalScrollDisabled(), scrollInAction]);
console.log(e);
if (verticalScrollDisabled() && !scrollInAction)
return;
console.log([verticalScrollDisabled(), scrollInAction]);
This code has been working for ever and nothing changed to it other than we in some seperate code are opening a popup and closing it again. Is there anything that could cause events to be doing something out of the expected related to if the window loses focus or something? Again, the test variable is not altered outside the verticalcrollDisabled function, so I have no clue why it can go change itself to false, notice the ["setting", true].
Just verified that the popup is not the cause.
Heres the hole file. https://gist.github.com/s093294/e49ed46d2680c1403e3b
Answer is, validate your assumptions.
I assumed that the file was not loaded twice since it being a module defined with define and loaded with requirejs. This didnt hold up since there was some ID mapping that made two ids load this file and as one of the comments said, this is the thing that makes it possible.
I resolved the requirejs configuration and problem vent away.
I'll be short with words, here's the situation:
for (var _im = 0; _im < slideshow._preloadbulks[slideshow._preloadCurrentbulk].length; _im++) {
var tmpSlideIndex = (slideshow._preloadCurrentbulk*slideshow._preloadMaxbulkSize)+_im;
slideshow._preloadSlides[tmpSlideIndex] = document.createElement('video');
slideshow._preloadSlides[tmpSlideIndex].autoplay = false;
slideshow._preloadSlides[tmpSlideIndex].loop = false;
slideshow._preloadSlides[tmpSlideIndex].addEventListener('canplaythrough', slideshow.slideLoaded, false);
slideshow._preloadSlides[tmpSlideIndex].src = slideshow._slides[tmpSlideIndex][slideshow.image_size+"_video_url"];
slideshow._preloadSlides[tmpSlideIndex].addEventListener('error', function(){
console.log(tmpSlideIndex);
slideshow._preloadSlides.splice(tmpSlideIndex,1);
slideshow._slides.splice(tmpSlideIndex,1);
slideshow.slideLoaded();
}, true);
}
As you can see, I have a video array and I'm loading each element src to the DOM to pre-load it.
It works just fine, but I have to deal with a situation when one resource is n/a, then I need to remove it from the existing arrays.
The addEventListener('error', works just fine, it detects the unavailable resource but when I'm logging tmpSlideIndex into the console I get a different value rather than the original slide index (because the loop continues).
I've tried setting the useCapture flag as you can see to the error handler, thinking that will do the trick but it won't.
Any tricks?
Thanks!
The issue is that when you are creating a closure over the tmpSlideIndex variable, it allows you to reference that variable inside the children function, but it's not creating a brand new variable, and since the loop continues and your error handler function executes asynchronously, the value of tmpSlideIndex will always be the last index of the loop. To keep the original value, we can create a self-executing function to wich we will pass the value of tmpSlideIndex. That self-executing function will effectively create a new scope and we will finally return a function that will create a closure over the slideIndex variable that lives in it's parent function scope.
slideshow._preloadSlides[tmpSlideIndex].addEventListener('error', (function(slideIndex) {
return function () {
console.log(slideIndex);
slideshow._preloadSlides.splice(slideIndex,1);
slideshow._slides.splice(slideIndex,1);
slideshow.slideLoaded();
};
})(slideIndex), true);
I'm trying to send data to a processing script. But for some reason the variable pjs below binds to the canvas "competence1" and enters the first if statement, but then the bindJavascript(this)-call returns error, but only in firefox. (works perfectly in chrome):
[pjs.bindJavascript is not a function]
var bound = false;
function initProcessing(){
var pjs = Processing.getInstanceById('competence1');
if (pjs != null) {
// Calling the processing code method
pjs.bindJavascript(this);
bound = true;
//Do some work
}
if(!bound) setTimeout(initProcessing, 250);
}
Environment: Mac OS X - Lion;
OBS! The bindJavascript(this)- method exists in the pde script loaded in the canvas-tag
By wrapping up all my script in a varable-map and by using the second way for setTimeout to be called i can follow each state and control the result.
So wrap it up-->
var ex = {
init : function(canId){
var canId = canId;
// check the if bound
// bind in this closure
// set new timer
}
}
setTimeout-->
setTimeout('ex.init("'+canId+'")', 2000);
and ofcourse add the parameter in so it can hold that value during it's own execution. So processing works just fine and i should use closure more often, that's the solution.
I had the same problem. I was using almost identical JS to you (which I got from the Pomax tutorial), and it was working fine. However, when I added the following preload directive (to load a backdrop), then suddenly my initProcessing function stopped working.
/* #pjs preload="metal_background.jpg"; */
The error message was the same: pjs.bindJavascript is not a function
On debugging, I could see that the pjs object did indeed not have a bindJavaScript function exposed, even though there is one declared in my PDE file.
It turns out this was purely down to timing... the preload had slowed down the initialisation of the processing object, so the second time round the 250ms loop, the pjs object existed, but didn't yet have its bindJavaScript function.
I am not 100% sure how Processing.js does this object construction, but in this case, a simple solution was just to check whether bindJavaScript actually was defined! I changed my code to the following:
var bound = false;
function initProcessing() {
var pjs = Processing.getInstanceById('mySketchId');
if(pjs != null) {
if(typeof(pjs.bindJavaScript) == "function") {
pjs.bindJavaScript(this);
bound = true;
}
}
if(!bound) setTimeout(initProcessing, 250);
}
After this it worked fine!