JavaScript function parameter error - javascript

I have this simple slideshow set up and it all works fine if I remove the parameters and add the class and speed manually.
If I use parameters to set the class and speed, it fails. With the first image getting the current class applied and then the dom seems to go crazy.
‘undefined’ pops up a lot although there are no errors in console.
Any help would be appreciated. Thanks
let pos = 0;
window.addEventListener("load", function(event) {
testIt('current', 5000);
});
function testIt(_class, _speed) {
const testPara = document.querySelectorAll('.bg_imgs');
let i;
for(i = 0; i < testPara.length; i++) {
testPara[i].classList.remove(_class);
}
pos++;
if(pos > testPara.length) {pos = 1;}
testPara[pos-1].classList.add(_class);
setTimeout(_class, _speed); }

It looks like you're sending the wrong parameters to setTimeout. It should take the form setTimeout(function, time), but instead, you're passing it what I assume is a string.
setTimeout(function() { testIt(_class, _speed); }, _speed);
should work

SetTimeout takes a function as its first param. If you are trying to delay the recursion try:
setTimeout(() => testIt(_class, _speed), _speed)
Thought window.requestAnimationFrame would be a better solution. More info on animation frame

Related

How can I change this into a loop instead of a recursive function?

So I have a piece of code like
var barlen = $('#SSWEprogressbar').width(),
$elems = $('[data-srcurl]'),
k = 0,
n = $elems.length;
LoadImage();
function LoadImage()
{
var $elem = $($elems[k]);
var img = new Image(),
url = $elem.attr('data-srcurl');
$(img).load(function(){
$('#SSWEloaderfront').attr('src',url);
$('#SSWEloadprogress').width((k+1)/n*barlen + "px");
var srctgt = $elem.attr('data-srctgt');
// change url to src attribute or background image of element
if ( srctgt == "srcattr" ){ $elem.attr('src',url); }
else if ( srctgt == "bgimg" ) { $elem.css('background-image',"url("+url+")"); }
// decide whether to exit the
if ( ++k == n ) { AllyticsSSWEPlayerShow(); }
else { LoadImage(); }
});
img.src = url;
}
and the reason I have it written that way is because load callback needs to be called before the stuff in the function can be executed again. If possible, I'd like to change this from a recursive function to a loop, but I don't know how to do that because there's no way to make a for or while loop "wait" before going on to the next iteration. Or is there?
As I mentioned in the comment you can easily resolve your problem, by using setTimeout(LoadImage, 100); in the else instead of calling the function directly. The 2nd parameter is the delay in ms.
If you understand why setTimeout(LoadImage, 0); is not stupid and not the same as calling the function directly then you understood setTimeout. It puts the function call in the queue, this means other events like clicks or keys that were pressed can be processed before the function is called again and the screen doesn't freeze. It's also impossible to reach max recursion like this, the depth is 1.

Javascript: uncaught typeerror undefined is not a function for object methods

I make a simple quiz game. Here is some relevan methods that i have inside one object.
But doesn't work. I always get an error within 'rightAnswerGot' function. Console drops
"uncaught typeerror undefined is not a function for object methods" for this.addVariantsHtml(this.updateCharacter());
BasicGame.Game.prototype = {
actionOnClick: function (button) {
var log;
if(button.value==this.char_bubble.text) {
setTimeout(this.rightAnswerGot,1000);
} else {
// wrong
swoshsound.play();
}
console.log(log);
},
rightAnswerGot: function (){
this.addVariantsHtml(this.updateCharacter());
},
addVariantsHtml: function(id) {
this.answer = this.getAnswersVariants(id);
for (var i = 0; i < 6; i++) {
this.button[i].value = this.answer[i]['trans'];
this.button[i].char_id = this.answer[i]['id'];
this.ans_text[i].setText(this.answer[i]['trans']);
}
},
updateCharacter: function() {
var i = this.getRandomCharacter();
console.log("updateCharacter: "+i + " " +this.chars[i]);
this.char_bubble.setText(this.chars[i].getPath());
return i;
}
}
The aim is to froze the game for a second, when user choose the right answer, and than go to next question. Any ideas why does it happens?
Thanks
Looks like a classic JavaScript scope issue to me. However as you've tagged this question as using Phaser, I would suggest you use a Phaser Timer event to avoid scope problems. Specifically:
setTimeout(this.rightAnswerGot,1000);
replace it with:
this.game.time.events.add(Phaser.Timer.SECOND, this.rightAnswerGot, this);
Which will create a single 1 second timer that fires only once, calling your function at the end of it. You can use 1000 instead of Phaser.Timer.SECOND of course.
I would image that whats happening is that its trying to call the this.addVariantsHtml method, before its calling this.updateCharacter and getting the ID.
So your probably expecting that when it runs, for it to be something like:
this.addVariantsHtml(1);
But its actually trying to run
this.addVariantsHtml(this.updateCharacter());
So just do this:
var id = this.updateCharacter();
this.addVariantsHtml(id);
Either that or you need to look into method chaining/piping, which is just complicated and doesnt need to be used for this situation, but is interesting :)
Ok I found something that made it work!!
Here is a solution:
actionOnClick: function (button) {
var log;
if(button.value==this.char_bubble.text) {
var context=this;
setTimeout(function() {
context.addVariantsHtml(context.updateCharacter());
},1000);
} else {
// wrong
swoshsound.play();
}
console.log(log);
},

Send setTimeout name, element id, and time as parameters of a function?

This is probably something really obvious, but I've searched around and tried a few things, and can't get it to work, so maybe someone can point out my error here.
I have a setTimeout that I will end up using over and over (and I know there is the setinterval, but I actually need to control when the timer starts and stops, and whether it starts again each time). Anyway, I figured if I'm writing it over and over, I should be able to use a function and pass it the parameters needed.
if ($('#selectRole').val() === 'Dispatch') {
//show Add Notes button
var funcAddNotesTimer = function(timerName,buttonName, timeToHide) {
console.log(timerName);
console.log(timeToHide / 1000);
timerName = setTimeout(function() {
$('buttonName').show();
}, timeToHide);
};
funcAddNotesTimer('addNotesTimer', '#disAddNotes', 30000);
I'm trying to set the timer function name to 'addNotesTimer', and when the timer is up I want to show the button with id #disAddNotes, and I want the timer to run for 30000 msec.
To me, what I have looks right, but I never get anything in my console log, so I don't think it's even getting into the function.
What am I doing wrong here?
I dont think its possible to use a string argument as the name of setTimeOut
Heres how you could approach it
// var timer = null; // dont really need that
var funcAddNotesTimer = function(buttonName, timeToHide) {
var timerName = setTimeout(function() {
//$('buttonName').show();
$(buttonName).show(); // buttonName is already a string so no need to add quotes around it.
}, timeToHide);
return timerName;
};
if ($('#selectRole').val() === 'Dispatch') {
var timer = funcAddNotesTimer('#disAddNotes', 30000);
// do something with timer
}
when you don't see any output in the console the reason must be something else(e.g. there is a bracket missing at the end of the code)
To set a variable with a dynamic name use the subscript-notation:
window[timerName] = setTimeout(/**/);
it will set a global variable named addNotesTimer.
As you currently do it you're simply overwriting the argument passed to the function.
Summary:
if ($('#selectRole').val() === 'Dispatch') {
//show Add Notes button
var funcAddNotesTimer = function(timerName,buttonName, timeToHide) {
console.log(timerName);
console.log(timeToHide / 1000);
window[timerName] = setTimeout(function() {
$(buttonName).show();
}, timeToHide);
};
funcAddNotesTimer('addNotesTimer', '#disAddNotes', 5000);
}

Change body background image with jQuery

I decided to make a function that changes the body background image after every 10 seconds.
function Background()
{
var Background_Stage;
switch(Background_Stage)
{
case 0:
{
$('body').css.('background', '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_1_TEST.png) no-repeat');
Background_Stage++;
setInterval(function(){Background()},10000);
}
case 1:
{
$('body').css.('background', '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png) no-repeat');
Background_Stage++;
setInterval(function(){Background()},10000);
}
case 2:
{
$('body').css.('background', '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png) no-repeat');
Background_Stage = 0;//Reset
setInterval(function(){Background()},10000);
}
}
}
However hen I did something like this
<body onload="Background()"></body>
It doesn't seem to do anything, this might be a dumb thing to ask for help with but this is the first I did when I was learning JavaScript, I should say that I used jQuery for most of this.
There's a few problems with your code:
The value of Background_Stage won't persist between calls to Background, and in any case, you never assign a value to Background_Stage.
Use setTimeout rather than setInterval. setTimeout will call the function once at the end of the allotted time. setInterval will keep calling the same function again and again until explicitly cancelled. The way you have it, you'll end up with lots of concurrent setIntervals running.
You don't need the '.' between css and the following parenthesis.
Finally, try not to repeat yourself, meaning that if you find yourself typing out more or less the same statements over and over, then you can probably make the code cleaner. Something like:
(function()
{
var bgCounter = 0,
backgrounds = [
"../../Styles/Callum_Project1/Images/BACKGROUND_1_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_3_TEST.png"
];
function changeBackground()
{
bgCounter = (bgCounter+1) % backgrounds.length;
$('body').css('background', '#000 url('+backgrounds[bgCounter]+') no-repeat');
setTimeout(changeBackground, 10000);
}
changeBackground();
})();
Now changing the background URLs or adding more is a simple job of editing the backgrounds array.
You can also try this:
function Background(){
var imgs = [
"../../Styles/Callum_Project1/Images/BACKGROUND_1_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_2_TEST.png",
"../../Styles/Callum_Project1/Images/BACKGROUND_3_TEST.png"
],
len = imgs.length,
idx = -1;
setInterval(function(){
idx = (idx+1)%len;
$("body").css("background", "#000 url("+imgs[idx]+")");
}, 10000);
}
Every time you call background, you instantiate a new local variable called Background_Stage with a value of undefined. This doesn't match any of your switch options.
You need to declare the variable outside of your function (so it persists between calls to the function) and give it a starting value.
Your Backgroud_Stage is not initialized
Your setInterval placement will cause very serious problems
There's also invalid syntax.
Overall, your code can be simpler like this:
var Stage = 0;
setInterval(function() {
var bg = '#000 url(../../Styles/Callum_Project1/Images/BACKGROUND_'+(Stage+1)+'_TEST.png) no-repeat';
document.body.style.background = bg;
Stage = ++Stage % 3;
}, 10000);

Callback function in for loop?

How do I get a function to run after all the fadeOuts in the for loop below?
What I need to do is fadeout anything that may be visible and then fadein a specific object. Due to styling requirements my topnav and dropdown nav are in to different uls which is why things are tricky.
I'm not very good at writing my own scripts yet so I'm (hopefully) missing something basic.
I've tried wrapping things in functions but that seems to mess with variable scope and screws things up that I don't understand...
Thanks for any help!
$('.ksddtop').on('mouseenter', function(){
var ddtop = $(this).text();
var dd = $('.' + ddtop);
$('.ksddwrap').fadeIn();
$(dd).fadeIn();
var ksdds = $('.ksdd');
for(var i = 0; i < ksdds.length; i++) {
var ksdd = ksdds[i];
if (! $(ksdd).hasClass(ddtop) ){
$(ksdd).fadeOut();
}
}
});
This should do it, if I understand the requirements:
$('.ksdd:not(' + ddtop + ')').fadeOut().promise().done(function(){
// all done fading!
});
Fade out all ksdd elements that don't have the ddtop class, then do something when they are all done animating.
More Information:
calling .promise on a jQuery collection gives you a promise object that will resolve when all animations on the collection of elements are complete. This includes queued animations.
If you instead passed a callback function directly to .fadeOut(), you would get a callback for each element rather than one after they were all done.
Instead of:
var ksdds = $('.ksdd');
for(var i = 0; i < ksdds.length; i++) {
var ksdd = ksdds[i];
if (! $(ksdd).hasClass(ddtop) ){
$(ksdd).fadeOut();
}
}
Try:
$('.ksdd').each(function(){
if (! $(this).hasClass(ddtop) ){
$(this).fadeOut();
}
});

Categories

Resources