Place parts of a for loop into function in javascript - javascript

I have several functions that use this given for loop below.
function startClaw(dir){
var readCount = 0;
for(var isRead in qdata){
readCount++;
if(qdata[isRead]['reading'] == true){
return;
}else if(readCount == 5){
isAnimating = $("#claw").is(':animated');
if(!isAnimating){// prevents multiple clicks during animation
if(isMoving || isDropping){ return; }
MCI = setInterval(function(){ moveClaw(dir); },10);
//console.log("startClaw:" + dir);
stopSwingClaw();
}
}
}
}
//.................................................................
function dropClaw(){
var readCount = 0;
for(var isRead in qdata){
readCount++;
if(qdata[isRead]['reading'] == true){
return;
}else if(readCount == 5){
if(isDropping){ return; } //prevent multiple clicks
stopSwingClaw();
isDropping = true;
MCI = setInterval(moveDown,20); //start heartbeat
}
}
}
Everything in the else if statement is different within the various functions. I'm wondering if there is any way to place the "pieces" of the for loop on the outside of the else if into its very own function. I feel like I've seen this or had done this a very long time ago, but it escapes me and I couldn't find any examples. Thanks everyone!

Previewing, I see this is similar to the above. Two differences (it looks like) are here the count gets passed to the function in case they needed to ever have different checks in the if statement, and, it's checking what the return value is since it looks like you return out of the loop if the condition is met. There are notes in comments in the code below.
function startClaw(dir) {
// Pass a function as a callback to the method which expects to receive the count as a param
doReadCount(qdata, function(theCount) {
if (theCount === 5) {
isAnimating = $("#claw").is(':animated');
if (!isAnimating) { // prevents multiple clicks during animation
if (isMoving || isDropping) {
return true;
}
MCI = setInterval(function() { moveClaw(dir); }, 10);
//console.log("startClaw:" + dir);
stopSwingClaw();
}
return false;
});
}
//.................................................................
function dropClaw() {
// Pass a function as a callback to the method which expects to receive the count as a param
doReadCount(qdata, function(theCount) {
if (theCount === 5) {
if (isDropping) {
return;
} //prevent multiple clicks
stopSwingClaw();
isDropping = true;
MCI = setInterval(moveDown,20); //start heartbeat
}
});
}
function doReadCount(qdata, elseFunction) {
var readCount = 0;
var elseReturn;
for (var isRead in qdata) {
readCount++;
if (qdata[isRead]['reading'] == true) {
return;
} else {
// call the function that was sent and pass it the current read count. If the return is true, then also return true here
elseReturn = elseFunction(readCount);
if (elseReturn) {
return;
}
}
}
}

You can pass a function into another function to achieve this. I've done it for dropClaw, and it should be clear from my example how to do also extract startClaw.
function operateClaw(func){
var readCount = 0;
for(var isRead in qdata){
readCount++;
if(qdata[isRead]['reading'] == true){
return;
}else if(readCount == 5){
func();
}
}
}
function drop () {
if(isDropping){ return; } //prevent multiple clicks
stopSwingClaw();
isDropping = true;
MCI = setInterval(moveDown,20); //start heartbeat
}
function dropClaw () {
operateClaw(drop);
}

Related

variable changing to true before setInterval is finished

showMoves is a function made to show flashing for a simon game.
When the flashing lights are over I clear the interval to stop it and then I set game.playerTurn to true so I can click on colors, but game.playerTurn is changing to true as soon as showMoves is activated.
I want game.playerTurn to stay false until the showMoves function is finished showing flashing.
Here are the functions I'm using game.playerTurn in -
game.playerTurn = false;
//for flashing lights
function showMoves() {
let i = 0;
const start = setInterval(function () {
if (i >= game.computerMoves.length) {
clearInterval(start);
game.playerTurn = true;
return;
}
const move = game.computerMoves[i];
setLight(move, true);
setTimeout(setLight.bind(null, move, false), 1000); //Using bind to preset arguments
i++;
}, 2000);
}
function setLight(color, isOn) {
if (isOn) {
sounds[color.id].play();
}
color.style.backgroundColor = isOn ? colors[0].get(color) : colors[1].get(color);
}
//compareMoves is fired everytime I click on a color
function compareMoves(e) {
if (e === game.computerMoves[game.counter]) {
game.counter++;
//This is if all the moves were chosen correctly
if (game.playerMoves.length === game.computerMoves.length && e === game.computerMoves[game.computerMoves.length - 1]) {
simonHTML.displayScore.textContent = ++game.score;
game.playerTurn = false;
resetMoves();
randomMoves(++game.turn);
showMoves();
game.counter = 0;
}
} else if (game.strict) {
//if your move was wrong do this
} else {
game.playerMoves = [];
game.counter = 0;
game.playerTurn = false;
showMoves();
return false;
}
}
I'd appreciate any help with this. Here is a link to the game and all the code https://codepen.io/icewizard/pen/JLBpNQ
Where are you setting game.playerTurn back to false?
function showMoves() {
game.playerTurn = false;
let i = 0;
const start = setInterval(function() {
if (i >= game.computerMoves.length) {
clearInterval(start);
game.playerTurn = true;
return;
}
const move = game.computerMoves[i];
setLight(move, true);
setTimeout(setLight.bind(null, move, false), 1000); //Using bind to preset arguments
i++;
}, 2000);
}
Seems to work for me in the codepen example you provided

Javascript Memory

I was wondering why my program crashes after its made its first match....any ideas would be greatly appreciated. Below is the code snippet. Thanks for the input!
var clicks = 0; //counts how may picks have been made in each turn
var firstchoice; //stores index of first card selected
var secondchoice; //stores index of second card selected
var match = 0; //counts matches made
var backcard = "deck.jpg"; //shows back of card when turned over
var faces = []; //array to store card images
faces[0] = 'pic1.jpg';
faces[1] = 'pic2.jpg';
faces[2] = 'pic3.jpg';
faces[3] = 'pic3.jpg';
faces[4] = 'pic2.jpg';
faces[5] = 'pic1.jpg';
function choose(card) {
if (clicks === 2) {
return;
}
if (clicks === 0) {
firstchoice = card;
document.images[card].src = faces[card];
clicks = 1;
} else {
clicks = 2;
secondchoice = card;
document.images[card].src = faces[card];
timer = setInterval("check()", 1000);
}
}
/* Check to see if a match is made */
function check() {
clearInterval(timer); //stop timer
if (faces[secondchoice] === faces[firstchoice]) {
match++;
document.getElementById("matches").innerHTML = match;
} else {
document.images[firstchoice].src = backcard;
document.images[secondchoice].src = backcard;
clicks = 0;
return;
}
}
The first parameter of setInterval needs to be a function not a string pretending to be a function. So you would want this:
timer = setInterval(function() { check(); }, 1000);
Of course, you can simplify:
timer = setInterval(check, 1000);
Not sure why you're using setInterval() here. You could more easily just do:
timer = setTimeout(check, 1000);
The advantage is there is no interval to clear in the check() function.
The other issue is that you are not resetting your 'clicks' counter to 0 when there is a match.
You want this:
function check() {
clearInterval(timer); //stop timer
if (faces[secondchoice] === faces[firstchoice]) {
match++;
document.getElementById("matches").innerHTML = match;
} else {
document.images[firstchoice].src = backcard;
document.images[secondchoice].src = backcard;
}
clicks = 0;
}
I think you have to declare you timer function globally. Its only defined in the scope of the first function, so in the second when you try to clear it nothing happens:
var timer = ''; //Declare timer up here first!
function choose(card) { ... }
function check() { ... }

Call function 3 only after functions 1 and 2 are done

How do i make sure function createOverzicht only is excecuted after functions
checkNotEmpty and checkNumber are done, now if i click on the button function createOverzicht its called, but thats not supposed to happen, createOverzicht is only supposed to be called after the first two functions or done.
In this case i have a form and the first two functions are to validate the input, so thats why i dont want createOverzicht o excecute when there is nothing filled in
so to simplify the concept this is what i mean:
function createOverzicht() {
if (checkNotEmpty && checkNumber) {
alert('hi');
};
else {
//do nothing
};
}
function checkNotEmpty(field, span) {
if (field.value.length > 1 && isNaN(field.value)) {
document.getElementById(span).className = 'goed';
document.getElementById(span).innerHTML = '<img src=\'../img/ok.png\'>';
} else {
document.getElementById(span).className = 'nietgoed';
document.getElementById(span).innerHTML = '<img src=\'../img/notok.png\'>';
};
};
function checkNumber(field, span) {
if (field.value.length == 10 && !isNaN(field.value)) {
document.getElementById(span).className = 'goed';
document.getElementById(span).innerHTML = '<img src=\'../img/ok.png\'>';
} else {
document.getElementById(span).className = 'nietgoed';
document.getElementById(span).innerHTML = '<img src=\'../img/notok.png\'>';
};
};
function createOverzicht() {
alert('hi');
}
window.onload = function() {
document.getElementById('naam').oninput = function() {
checkNotEmpty(this, 'meldingNaam');
};
document.getElementById('achternaam').oninput = function() {
checkNotEmpty(this, 'meldingAchternaam');
};
document.getElementById('telefoonnummer').oninput = function() {
checkNumber(this, 'meldingTel');
};
document.getElementById('overzicht').onclick = function() {
createOverzicht()
};
};
As far as I can see you have two options:
1) store the status(valid or invalid) of each input
This could be hard to maintain!!
2) Inside "createOverzicht" call a function that check if everything is Ok
This alternative will imply make some changes in the functions that validate, you will need that they return true if the field is valid or by the contrary false; also add some code at the beginning of "createOverzicht".
The implementation will look like:
function createOverzicht() {
checkNotEmpty(document.getElementById('naam'), 'meldingNaam');
checkNotEmpty(document.getElementById('achternaam'),'meldingAchternaam');
checkNumber(document.getElementById('telefoonnummer'), 'meldingTel');
alert('hi');
}
function checkNotEmpty(field, span) {
if (field.value.length > 1 && isNaN(field.value)) {
document.getElementById(span).className = 'goed';
document.getElementById(span).innerHTML = '<img src=\'../img/ok.png\'>';
return true;
} else {
document.getElementById(span).className = 'nietgoed';
document.getElementById(span).innerHTML = '<img src=\'../img/notok.png\'>';
return false;
};
};
function checkNumber(field, span) {
if (field.value.length == 10 && !isNaN(field.value)) {
document.getElementById(span).className = 'goed';
document.getElementById(span).innerHTML = '<img src=\'../img/ok.png\'>';
return true;
} else {
document.getElementById(span).className = 'nietgoed';
document.getElementById(span).innerHTML = '<img src=\'../img/notok.png\'>';
return false;
};
};
May be use a javascript library like jQuery for this, the jQuery Validator plugging will help you a loot.
You need to move the call to createOverzicht() like this:
function myFunction() {
if (checkNotEmpty && checkNumber) {
createOverzicht();
};
else {
//do nothing
};
}
Also the checkNotEmpty and checkNumber functions need to return a Boolean value.

setTimeout doesn't seem to be calling the function

The code worked great until I added the setTimeout. Now, no matter how I attempt to call the functions in setTimeout ( setTimeout(function(){fadeOut()},1000); setTimeout("fadeOut()",1000); etc ) it doesn't seem to get to the function at all.
I'm a Javascript newbie so any and all help is appreciated =]
javascript code:
var slideArray = ["slide1","slide2","slide3","slide4","slide5","slide6"];
var currentSlide = null;
var current = null;
var done = false;
function fade(newSlide)
{
if(currentSlide === null)
{
currentSlide = slideArray[0];
document.getElementById(currentSlide).style.opacity = 1.0;
for(var i=1;i<slideArray.length;i++)
document.getElementById(slideArray[i]).style.opacity = 0.0;
}
current = document.getElementById(currentSlide);
done = false;
do
{
window.setTimeout(fadeOut,1000);
} while(done == false);
currentSlide = newSlide;
current = document.getElementById(currentSlide);
done = false;
do
{
window.setTimeout(fadeIn,1000);
} while(done == false);
}
function fadeOut()
{
if(parseFloat(current.style.opacity)-0.1>.0000001)
{
current.style.opacity = parseFloat(current.style.opacity) -0.1;
done = false;
}
else
{
current.style.opacity = 0.0;
done = true;
}
}
function fadeIn()
{
if(0.9-parseFloat(current.style.opacity)>.0000001)
{
current.style.opacity = parseFloat(current.style.opacity)+0.1;
done = false;
}
else
{
current.style.opacity = 1.0;
done = true;
}
}
You can't use this structure:
do
{
window.setTimeout(fadeIn,1000);
} while(done == false);
Because the code in the setTimeout() runs sometime LATER, your value of done will NEVER be changed and this loop will run forever. And, as long as it runs, the setTimeout() never gets to fire either (because javascript is single threaded).
Instead, what you should do is launch the next setTimeout(fadeIn, 1000) from the fadeIn() function if you aren't done.
function fadeOut()
{
if(parseFloat(current.style.opacity)-0.1>.0000001)
{
current.style.opacity = parseFloat(current.style.opacity) -0.1;
setTimeout(fadeOut, 1000);
}
else
{
current.style.opacity = 0.0;
}
}
Remember that javascript is single-threaded, so your setTimeout'et functions will not be called until it is finished running the current script. Which will never happen since you're in a loop that's never gonna end (untill you're out of memory from all those setTimeout's). Just call setTimeout once and let the function return. And forget the idea of waiting for it to have happened.

Returning false in Javascript/Jquery within an if statement

I've got this function to check my form:
function checkFrm() {
$.each($('select'), function() {
var $this = $(this);
if( $this.val() === 'null') {
// do nothing
} else {
if($this.next('input').val().length < 1) {
return false;
}
}
});
}
When the user submits this, it runs this code, and ideally if the criteria is met the form won't submit because of the 'return false;' bit.
However, for some reason it's completley ignoring this!
If I set a return variable at the start like 'var toreturn = true;' then set 'toreturn = false' when the trigger is hit, then 'return toreturn;' right at the end it stops the form submitting just fine... however that's not much use, as the alerts and checks I run in between are all triggered at once which would be completely overwhelming for the user.
Any suggestions please?
Cheers :)
Returning false from the each will not return false from the function.
You will need to set a var to return false from the function also. You can still break out of the each by using return false as soon as your condition fails.
function checkFrm() {
var retVal=true;
$.each($('select'), function() {
var $this = $(this);
if( $this.val() === 'null') {
// do nothing
} else {
if($this.next('input').val().length < 1) {
//set the var to return from the function
retval = false;
//exit out of the each
return false;
}
}
});
return retVal;
}
When you call return false; it refurns false for the function
function() {
var $this = $(this);
if( $this.val() === 'null') {
// do nothing
} else {
if($this.next('input').val().length < 1) {
return false;
}
}
}
That is not work for you.
You better get an array of selects like this:
var selectsArray=document.getElementsByTagName("select");
and work with them in a loop.
for(var i=0; i< selectsArray.length;i++){
if( selectsArray[i].value === 'null') {
// do nothing
} else {
if(selectsArray[i].next('input').val().length < 1) {
return false;
}
}
}

Categories