break from while loop from anonymous function - javascript

I am new to javascript, my background is python and ruby and I am having issues dealing with javascript anonymous functions, my problem is the following:
I have an element in the page which has an attribute value (true/false), I need to keep performing an action until this attribute changes value.
the code that I tried out is below, as you could guess, the break won't quit the loop if result.value == true... Any idea if I am in the right direction?
var counter = 0;
while (counter < 5) {
this
.click('#someelementid')
counter++;
this
.getAttribute('#someelementid', 'disabled', function(result) {
if (result.value == 'true') {
this.break;
}
}.bind(this));
this.api.pause(1000);
};
My assumption is that by binding this, I have access to the while block? Please correct me if I am wrong.

Have you tried changing your code to something like below ?
var counter = 0;
var arr = [1, 2, 3, 4, 5];
while (counter < 5) {
arr.forEach(
(element) => {
if (counter < 5) { // if you don't have this it will print all 5, else it prints only 3
console.log('Element value:', element);
}
if (element == 3) {
counter = 5;
}
}
);
}
What happens is this:
When you enter the while loop it will enter the forEach loop and start iterating, when it reaches element == 3 it will set counter to 5, but it still has to finish the current forEach loop, once it does it wont perform another while loop therefore exiting it.
So changing your code to:
var counter = 0;
while (counter < 5) {
this
.click('#someelementid')
counter++;
this
.getAttribute('#someelementid', 'disabled', function(result) {
if (result.value == 'true') {
counter = 5; // This should do the trick (without 'this')
}
}.bind(this));
this.api.pause(1000);
};

The break inside a function would not break the loop outside the function.
Through getAttribute() get the result inline instead of having a callback. then you can break the function.
Or
Have a global variable. breakLoop = false; set it to true; inside the callback function. And put a check on this variable in the while loop. while(!breakLoop ..)
Another approach.
Don't have a loop altogether.
var counter = 0;
function doSomething(){
this.click('#someelementid');
counter++;
this.getAttribute('#someelementid', 'disabled', function(result) {
if(result.value != 'true' && counter<5){
this.api.pause(1000);
doSomething();
}
}.bind(this);
};

Related

How can I set timers in slideshow to show as selected?

I have to create a slideshow, using an array of images and have that set on a timer. There is a drop-down menu with slow, medium, and fast options and the pictures need to transition with accordance to the drop down option selected. Whenever I execute this code in a web browser the code repeats itself, while doubling, as I read the value of i in the console.
I have tried using a while and a do-while loop to have the images on a rotation.
I have also tried putting the if-statements outside and below/above the function.
<script>
var i = 0;
function changeImg(){
if (x == 'slow'){
setInterval("changeImg()", 5000);
} else if (x == 'medium'){
setInterval("changeImg()", 3000);
} else if (x == 'fast') {
setInterval("changeImg()", 1000);
} else {}
while (i < 3){
console.log(i);
document.slide.src = sportsArray[i];
i++;
}
console.log(i);
console.log(sportsArray);
}
</sctipt>
First, I would read up on MDN's docs on setInterval() and clearInterval to fill in the knowledge gaps that lead you to approach the problem this way.
You are recursively calling changeImg() in your code which I believe is causing the issue you describe as:
the code repeats itself, while doubling, as I read the value of i in the console
Also, your while loop will run immediately when calling changeImg() which also does not appear to be desired in this situation.
setInterval() mimics a while loop by nature. There is no need for a while loop in this code. Below is a solution that I hope you can use as a reference. I separated the code to determine the interval into a function the getIntervalSpeed.
function changeImg(x) {
var getIntervalSpeed = function(x) {
if (x === 'slow') {
return 5000;
} else if (x === 'medium') {
return 3000;
} else if (x === 'fast') {
return 1000;
} else {
return 3000;
// return a default interval if x is not defined
}
};
var i = 0;
var slideShow = setInterval(function() {
if (i >= sportsArray.length) {
i = 0; // reset index
}
document.slide.src = sportsArray[i]; // set the slide.src to the current index
i++; // increment index
}, getIntervalSpeed(x));
// on click of ANY button on the page, stop the slideshow
document.querySelector('button').addEventListener('click', function() {
clearInterval(slideShow);
});
}

Most efficent way to code branches in Javascript

Say I have a Javascript array which contains numbers between 0 and 5. Each of the numbers is really an instruction to call a specific function. For example:
var array = [lots of data];
for(i=0; i<array.length; i++){
if(i == 0){ function0(); };
if(i == 1){ function1(); };
if(i == 2){ function2(); };
if(i == 3){ function3(); };
if(i == 4){ function4(); };
if(i == 5){ function5(); };
}
This seems like an awful lot of branching and unnecessary checks. What would be a more performance minded way to call the function?
I've thought about dynamically creating the function names using eval, but isn't there a better way?
Store the functions in the array;
var array = [function0, function1, ..., functionN];
and then just call the functions on each iteration:
for (var i=0; i<array.length; i++) {
array[i]();
}
Use an Object as a map, or use the switch statement. The former is demonstrated below.
const functionMap = {
0: function0,
1: function1,
2: function2
};
array.foreach(i => functionMap[i]());
Alternatively, if you can know the name of the function based off of i, you can call it from the parent scope, e.g.
window[`function${i}`]()
However, strictly speaking, manually coding in the if statements (or using a switch) may be the most performant. I doubt there will be a significant performance difference between any of them.
Functions can be called as strings, so window['function' + i]() would work, and call a function. This can be very dynamic.
var array = [0, 1, 2];
function function0() { console.log('Function 0') }
function function1() { console.log('Function 1') }
function function2() { console.log('Function 2') }
for (i = 0; i < array.length; i++) {
if (typeof window['function' + i] == 'function') {
window['function' + i]()
}
}

Javascript Click Event Pushing Multiple Duplicates to Array

In recreating the Simon game, I am trying to push a click event to an array and then immediately test that Array in a nested function. On the first pass it seems to work.
However, on the third run the array does not seem to clear.
The screen shot below also shows that each input is printed multiple times to the console.
Full code pen here - https://codepen.io/jhc1982/pen/NwQZRw?editors=1010
Quick example:
function userMoves() {
var userInput = [];
document.getElementById("red").addEventListener("click", function(){
userInput.push("red");
testington();
});
$(".red").mousedown(function(event){
redAudio.play();
$(".red").css("background-color", "red");
});
$(".red").mouseup(function(){
$(".red").css("background-color", "#990000");
});
function testington(){
if (userInput.length == pattern.length) {
for (var i = 0; i < userInput.length; i++) {
if (userInput[i] !== pattern[i]) {
alert("Game Over");
} else if (i === userInput.length -1 && userInput[i] === pattern[i]) {
userInput = emptyArr;
simonMoves();
console.log("user input is ",userInput);
} else {
continue;
}
}
}
}
}
I am sure it is something really obvious but have been stuck for hours.
I think the problem may be that you are assigning the click events every time the userMoves execute. That means every time the function is called the event is added to the elements, so after two calls to userMoves() when you click on red the event is executed twice, after three calls it is executed three times, etc.
The code that adds the event listener should be out of the userMoves function. The testington function should also be out of userMoves, which would get much simpler:
function userMoves() {
$("#score-text").text(level);
userInput = [];
}
Here's a Pen with working code: https://codepen.io/anon/pen/ppzqyY
You need to add the break; keyword to after alert("Game over");
function testington(){
if (userInput.length == pattern.length) {
for (var i = 0; i < userInput.length; i++) {
if (userInput[i] !== pattern[i]) {
alert("Game Over");
break; // Break the loop
} else if (i === userInput.length -1 && userInput[i] === pattern[i]) {
userInput = emptyArr;
simonMoves();
console.log("user input is ",userInput);
} else {
continue;
}
}
}
}

Need an explanation on simple code

$('#ID').on('click', function() {
if(!CommonUtil.compareDateById('startDt','endDt',false, false, true)) {
return false;
}
var cnt = 0;
if(!CommonUtil.isNullOrEmptyById('startDt')) { cnt++; }
if(cnt == 0) {
CommonUtil.setFocusById('srchWord','<spring:message code="confirm.input" arguments="XXXX"/>');
return false;
So if I click on #ID, following logic occurs.
And my question is what does
var cnt = 0;
if(!CommonUtil.isNullOrEmptyById('startDt')) {
cnt++;
}
mean?
The function of isNullOrEmptyById is following:
isNullOrEmptyById: function(id) {
var value = this.getTrimValueById(id);
return this.isNullOrEmpty(value);
},
But what does
cnt++;
do in here??
This is just an if conditional block:
if(!CommonUtil.isNullOrEmptyById('startDt')) {
cnt++;
}
So if CommonUtil.isNullOrEmptyById('startDt') resolves to false, then the condition resolves to true and the code in the block is executed:
cnt++;
The ++ operator increments the value. So whatever numeric value is in cnt will be incremented by 1.
In the overall context of the code, it seems to be treating cnt as more of a boolean than an integer, though. Unless there's more code outside of this example, this can be simplified by using this condition for the last conditional block instead of using cnt and then checking its value.
It is actually unnecessary. Since the cnt is only incremented once it's value is either 0 or 1. Instead you could just get rid of all that and use isNullOrEmptyById function.
if(!CommonUtil.isNullOrEmptyById('startDt')){
CommonUtil.setFocusById('srchWord','<spring:message code="confirm.input" arguments="XXXX"/>');
return false;
}

Asyncronous variables outside a for loop

I'm just starting out with AJAX and I'm trying to get a variable to be set inside a for loop. Then I want to call that variable later and use it's value.
Of course this would be synchronous, requiring the scripts to stop executing in order to run the loop before returning the new value of the function.
I'm hoping someone knows a better way to get the value from the for loop AFTER the for loop has run and use it in my code directly after that.
I would prefer not to use the setTimeout() hack to bypass this issue (it is a hack after all).
var getCount = function getCount(res) {
count = { active: 0, closed: 0 }; //Variable defined here
for(i=0; i<=res.length; i++) {
if(res[i].status == 'active') {
count.active ++;
} else { count.closed ++; }
}
return count; //And returned here
};
getCount(result);
console.log(count); //Here's where I need the result of the for loop
//Currently this outputs the count object with both properties set to 0;
I am not sure what AJAX has to do with your issue.
You are not assigning the result of the getCount function to the count variable (Unless you intended the count variable to be global, but in that case you need to define it before the getCount function definition).
Change this line:
getCount(result);
to this:
var count = getCount(result);
And you should be alright. :)
I would also suggest, when declaring variables, always declare them with var. In your case:
var count = { active: 0, closed: 0};
I don't know why you mention AJAX since there is nothing async about your code.
From what I see in your sample I don't see what all the difficulty is about.
Just use it as any other function.
function getCount(res) {
var count = { active: 0, closed: 0 }; //Variable defined here
for(i=0; i<=res.length; i++) {
if(res[i].status == 'active') {
count.active ++;
} else { count.closed ++; }
}
return count; //And returned here
};
console.log(getCount(result)); //Here's where I need the result of the for loop
First off, you had an extra = sign that was over-extending your for loop. I don't know if this answers your asynchronous issue, but here is how I would do it:
// sample object
var result = [
{status:"active"},
{status:"not-active"},
{status:"active"}
];
// kick off the function to get the count object back
var counts = getCount(result);
console.log(counts);
function getCount(res) {
var count = { active: 0, closed: 0 }; //Variable defined here, make sure you have var to keep it from going global scope
for(i=0; i<res.length; i++) { //here you had a wrong "="
if(res[i].status === 'active') {
count.active ++;
} else { count.closed ++; }
}
return count; //And returned here
}
Example here.

Categories

Resources