I am trying to using a for loop for trying to validate the input of the user and this is the code i got.
function Valid() {
objfieldid = ["userMail", "userCont"]
objboxid = ["cancelMail", "cancelCont"]
return objfieldid.every(callnonvalid)
}
function callnonvalid(id) {
var valid = false
var objlength = objfieldid.length
objlength--;
for (var i = objlength; i >= 0; i--){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i); //return 1, 1
return true
} else {
return false
}
}
}
As you can see, in the code, the for loop is running twice. but the i variable is left unchanged. Why would this happen?
btw, I did read different material about closure and i am sure there didnt got a closure problem
EDIT:guys please note that i did noticed the array is zero based, and i did minus the objlength by one.
Mistakes were found after checking the code carefully. The Mistake that I made was that I should not use the return for the out since that would stop the function from working, however that array.every Called the function twice which make the i not decreasing
I'm not sure why you're decrementing in your loop, because the performance gain would be infinitesimally small (it may even be slower, e.g. in Chrome/V8) and working in reverse order can get confusing further down the line, but that's your choice and I don't know enough about what you're doing to judge.
Either way, I don't think you'd want to decrement objlength before the loop begins as you are doing now. The whole point of a loop is to handle the incrementing/decrementing in the condition statement of the loop.
You would only decrement manually like that if you were going to move your if/else if/else statement into a closed over function and execute it recursively, decrementing the objlength from within the closure. Which would work, but it's unnecessarily complicated for what you're doing and you would gain nothing for rewriting the whole thing.
So, sticking with the looping approach, perhaps try either of these:
function Valid() {
objfieldid = ["userMail", "userCont"];
objboxid = ["cancelMail", "cancelCont"];
return objfieldid.every(callnonvalid);
}
function callnonvalid(id) {
var valid = false;
var objlength = objfieldid.length;
for(var i = 0; i < objlength; i++){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i);
return true;
} else {
return false;
}
}
}
or, if you want to decrement, use while instead of for:
function Valid() {
objfieldid = ["userMail", "userCont"];
objboxid = ["cancelMail", "cancelCont"];
return objfieldid.every(callnonvalid);
}
function callnonvalid(id) {
var valid = false;
var i = objfieldid.length;
while(i--){
var cobj = document.getElementById(objboxid[i]).checked;
if (document.getElementById(id).value != "" ){
var obj = document.getElementById(id).value;
} else if (cobj == true) {
alert(i);
return true;
} else {
return false;
}
}
}
Because the array objboxid[] has only two elements, the first time through your loop objboxid[2] will be attempting to fetch an array index that is out-of-bounds.
You probably meant something like:
for (var i = objlength; i > 0; i--){
var cobj = document.getElementById(objboxid[i-1]).checked;
or perhaps
for (var i = objlength-1; i >= 0; i--){
var cobj = document.getElementById(objboxid[i]).checked;
Related
i have been try to solve the sudoku with Blacktracking algo, everything is good, canvar is called and i able to see the number but the things is number are not moving i.e the logic is not exectuing
current.i === 0; is where i'm get the error! even i have declared a sperate variable for the num also the problem is not sloved. only if i remove the .num current == 0 than its not showing any error but still the number is not moving
enter image description here
var cell = [];
var stack = [];
var sudoku = [2,3,0,9,4,0,6,7,0,
8,0,0,3,2,5,9,1,4,
9,0,0,7,6,0,3,2,0,
1,0,0,0,0,0,7,9,2,
5,0,3,2,1,0,4,8,6,
4,0,0,6,8,0,5,3,1,
7,0,0,1,0,0,0,0,9,
6,5,9,8,7,2,1,4,3,
3,0,0,0,9,0,0,0,7];
var current;
var number = 1;
function setup(){
createCanvas(450,450);
var a=0;
var b=0;
for(var i=0;i<81;i++){
if(a%9==0 && i!=0){
b = b+50;
a = 0;
}
each[i] = new each(a,b,i,sudoku[i]);
a = a+50;
}
current = cell[0];
}
function draw(){
background(10);
for(var i=0;i<81;i++){
each[i].show();
}
if(current.num === 0){ //the error is typeerror can't read the property of num
if(! sameColumn(current.i,number) && ! sameRow(current.i,number) && ! sameSquare(current.i,number) && number<(10)){
current.num = number;
stack.push(current);
number = 0;
current.each[current.i+1];
}
else {
if(number > 8){
current.num = 0;
current = stack.pop();
number = current.num;
current.num = 0;
}
}
}
else{
current = each[current+1];
number = 0;
}
number++;
}
function each(a,b,i,num){
this.a = a;
this.b = b;
this.i = i;
this.num = num;
this.show = function(){
noFill();
stroke(255);
rect(this.a,this.b,50,50);
textSize(32);
text(this.num,a+12,b+40);
}
}
The error is pretty much straight forward. current = cell[0]; becomes undefined since you defined cell as an empty array and didn't manipulated it after that.
From what I have observed so far, many parts of your code logically does not work, for example,
same Column(current.i,number) && ! sameRow(current.i,number) && ! sameSquare(current.i,number)
will definitely throw you an error is it is executed (it is not since the execution does not reach to that line), unless you have a separate js file that contains these functions.
Another one is
current = cell[current+1];
if the current variable is to store the cell object, it does not make sense to add 1 to it, and vice versa.
Now I believe this is how setup function was meant to look like:
function setup(){
createCanvas(450,450);
var a=0;
var b=0;
for(var i=0;i<81;i++){
if(a%9==0 && i!=0){
b = b+50;
a = 0;
}
cell[i] = new Cell(a,b,i,sudoku[i]); //changed each[i] to cell[i], also renamed the 'each' class
a = a+50;
}
current = cell[0];
}
If possible, please edit in a little more information about what exactly does your code do. Cheers :)
I'm relatively new to customizing Google sheets and only learning javascript.
I'm trying to create a custom function that will search for a value in an array and return a string (something like vlookup).
What I'm trying to achieve is to get the value checked against multiple arrays. I wrote the below but for some reason, it checks only first element of the array (it did work but stopped for some reason and I cannot figure out why as I don't think I changed anything).
The second part will be trickier still, how to make it work against multiple arrays... I was thinking to create an array:
depots = [depot1,depot2...] and then change the code to "depots.length in for loop but even 1 array proves to be problematic.
var depot1 = ["device1", "device2", "device3"];
var depot1 = ["device1", "device2", "device3"];
function _depot(value) {
if (value) {
var depotCheckCase = value.toUpperCase();
for (var i = 0; i < depot1.length; i++) {
if (depotCheckCase == depot1[i]) {
return "Depot 1";
} else {
return false;
}
}
}
}
It only checks the first entry because you have return in both branches of your if/else, so no matter what, the first loop iteration will terminate the function.
Instead, move the return false; to the end, outside of the loop.
A couple of other issues:
You're declaring the same variable twice. Your second var depot1 = ... ends up being just an assignment (but since the array it's assigning has the same entries as the first one, you may not notice).
You're forcing the value to check to upper case, but not doing the same to the entry you're checking against.
Addressing all of those:
var depot1 = ["device1", "device2", "device3"];
function _depot(value) {
if (value) {
var depotCheckCase = value.toUpperCase();
for (var i = 0; i < depot1.length; i++) {
if (depotCheckCase == depot1[i].toUpperCase()) {
return "Depot 1";
}
}
return false;
}
}
console.log(_depot("device2")); // "Depot 1"
console.log(_depot("device8")); // false
Any idea how can I combine it with checking against second/third array?
You have two options:
Additional loops (simplest).
Finding the length of the longest array, using that as the loop max, and checking against undefined before comparing. Since [n] on an array when n is greater than or equal to the length will give you undefined, you can check that before doing the toUpperCase.
Here's that second one:
var depot1 = ["device1", "device2", "device3"];
var depot2 = ["device4", "device5"];
var depot3 = ["device6", "device7", "device8", "device9"];
function _depot(value) {
if (value) {
var depotCheckCase = value.toUpperCase();
var max = Math.max(depot1.length, depot2.length, depot3.length);
var entry;
for (var i = 0; i < max; i++) {
entry = depot1[i];
if (entry !== undefined && depotCheckCase === entry.toUpperCase()) {
return "Depot 1";
}
entry = depot2[i];
if (entry !== undefined && depotCheckCase === entry.toUpperCase()) {
return "Depot 2";
}
entry = depot3[i];
if (entry !== undefined && depotCheckCase === entry.toUpperCase()) {
return "Depot 3";
}
}
return false;
}
}
console.log(_depot("device2")); // "Depot 1"
console.log(_depot("device8")); // "Depot 3"
console.log(_depot("device5")); // "Depot 2"
console.log(_depot("device10")); // false
You could give yourself an array of arrays and do that in a loop rather than repeating the logic. I leave that as an exercise for the reader. :-)
I do understand how the following function works in general. BUT why doesn't it exit after the first iteration (when there is a palindrome)? It checks the first character against the last in the if statement, which is true, what should (in my logic) execute the return statement... Thank you for any help explaining this! :)
function palindrome(str) {
var lowerCaseStr = str.toLowerCase();
for (var i = 0; i < lowerCaseStr.length; i++)
debugger;
if (lowerCaseStr[i] === lowerCaseStr[lowerCaseStr.length - i - 1]){
return true;
}
return false;
}
It doesn't exit after the first iteration but after lowerCaseStr.length iterations because your code is equivalent to the code below
function palindrome(str) {
var lowerCaseStr = str.toLowerCase();
for (var i = 0; i < lowerCaseStr.length; i++){
debugger;
}
if (lowerCaseStr[lowerCaseStr.length] === lowerCaseStr[-1]){
return true;
}
return false;
}
that is, it iterates lowerCaseStr.length; times but the only thing it does for each iterates is call debugger after that it tests to elements in the array that doesn't exists. (Both indices are out of bounds). That results in a comparison of two times undefined undefined === undefined which is always true.
As a side node if you return either true or false depending on a boolean expression then consider using one return statement instead:
return (lowerCaseStr[i] === lowerCaseStr[lowerCaseStr.length - i - 1]);
You need to switch the logic, check for inequality and return false. If you reach the end, return true.
function palindrome(str) {
var lowerCaseStr = str.toLowerCase();
for (var i = 0; i < lowerCaseStr.length; i++) {
debugger;
if (lowerCaseStr[i] !== lowerCaseStr[lowerCaseStr.length - i - 1]) {
return false;
}
}
return true;
}
I tried using break Statement. but didnt worked out. I wanted to break out from outer loop as soon as some condition matches in inner loop.
angular.forEach(myfilejob, function(fieldMapO) {
var count = 0;
angular.forEach(myfilejob, function(fieldMapI) {
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
count ++;
}
});
if(count>1){
$scope.dups = true;
// tried break , but didnt work
}
else{
$scope.dups = false;
}
});
When you use forEach, there is no way to pause iteration - not even by using return. If you want a way to stop iteration in the middle of your loop, you must use an actual for or while loop (probably something like for..in or for..of or a traditional three-statement for(var i = 0; i < whatever; i++ loop if myfilejob is an array).
However, once you have done that, you can then label the loops to get the exact effect you're looking for:
outerDupLoop:
for (var outerIndex in myfilejob) {
var fieldMapO = myfilejob[outerIndex];
var count = 0;
innerDupLoop:
for (var innerIndex in myfilejob) {
var fieldMapI = myfilejob[innerIndex];
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
count ++;
}
});
if(count>1){
$scope.dups = true;
break outerDupLoop; // break from the outer loop
} else {
$scope.dups = false;
}
}
(Never mind that the break statement you were trying to add was in the outer loop anyway - removing the labels from this example would make this functionally equivalent. Did you mean to refactor the (count > 1) check so that it would work properly inside the inner loop?)
You can use return, which will essentially break out of the loop. If you want to do it within the inner loop, set a boolean to true, and check for it in the outer loop.
var dupsExist = false;
angular.forEach(myfilejob, function(fieldMapI) {
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
dupsExist = true;
return;
}
});
if (dupsExist){
return;
}
I suggest you define a bool when your inner condition is satisfied
angular.forEach(myfilejob, function(fieldMapO) {
var count = 0;
var conditionFlag = false;
angular.forEach(myfilejob, function(fieldMapI) {
if(fieldMapO.key == fieldMapI.key){
$scope.dupKey = fieldMapI.key;
count ++;
//condition is fulfilled so boolean is true now
conditionFlag = true
return false
}
});
if(count>1){
$scope.dups = true;
}
else{
$scope.dups = false;
}
//check if condition is satisfied then exit outer loop too
if(conditionFlag){
return false;
}
});
Hope it helps
I'm fairly new to JS and am still slightly confused, by the ordering and nesting of JS functions. I have a script that I want to occur in a specific way. The problem a criteria can be left blank by a user. Im trying to say if the variable length is greater than zero run the callback, but then move into the code that occurs under the next two if statements. I know there must be a more efficient method for this, but for the life of me I can't think of one besides placing all the other code under each different if/else statement.
var lst = []
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
d3.csv("kyle.csv", function (d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function (error, rows) {
if (dateu.length > 0) {
for (var i = 0; i < rows.length; i++) {
if (rows[i].date === dateu) {
lst.push(rows[i]);
console.log(rows[i]);
}
}
} else {
if (cityu.length > 0) {
for (var i = 0; i < lst.city.length; i++) {
if (lst.city[i] === cityu) {
lst2.push(lst[i]);
console.log(lst2);
}
}
} else {
if (numberu.length > 0) {
for (var i = 0; i < rows.length; i++) {
if (lst.number[i] === numberu) {
lst3.push(lst2[i]);
console.log(lst3);
}
}
}
}
}
})
};
Here you can see that if the dateu variable has length greater than zero the rows in a csv matching that user entered criteria will be pushed to the array "lst". Obviously it currently doesn't move into the next callback under, it will only do this if "dateu" equalled zero.
One other issue with my script is that at each if statement I hope to reduce my original input based on the user entered parameters. For example a user might enter "seattle" the variable "city" will now equal seattle and only rows containing Seattle as their city will be kept in the array that rows[i] is pushed to.
Every piece of user input shown here:
alert(cityu);
alert(dateu);
alert(numberu);
will have the same affect on the dataset, each time reducing the number of rows included.
The problem specifically is that each if statement relies on the array from the previous callback.
Your code redone a little - I've removed the else blocks, because you want to do each loop regardless of the previous loop
if(condition1) {
do something
}
else {
do something else
}
from that, if the first condition is met, the else block wont get executed
if(condition1) {
do something
}
if(condition2) {
do something else
}
In this case, do something else only relies on condition2 being true, consition1 is irrelevant
var lst = []
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
d3.csv("kyle.csv", function(d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function(error, rows) {
var i;
if (dateu.length > 0) {
for (i = 0; i < rows.length; i++) {
if (rows[i].date === dateu) {
lst.push(rows[i]);
console.log(rows[i]);
}
}
}
if (cityu.length > 0) {
for (i = 0; i < lst.city.length; i++) {
if (lst.city[i] === cityu) {
lst2.push(lst[i]);
console.log(lst2);
}
}
}
if (numberu.length > 0) {
for (i = 0; i < rows.length; i++) {
if (lst.number[i] === numberu) {
lst3.push(lst2[i]);
console.log(lst3);
}
}
}
});
};
One minor inconsequential change, moved the declaration of var i to the top of the function block, because technically you were declaring it three times, and jslint/jshint would complain - though nothing would break (yet)
I'm still not completely sure on your logic, but looking at Tiny Giant's gist, it seems like there are only three combinations:
1) Only dateu exists.
2) dateu and cityu exist.
3) dateu, cityu, and numberu exist.
So you don't care about the condition where dateu and numberu exist, but cityu is empty, right?
Okay, I reread your code. It seems like you have rows, and you have three possible filters. Filter rows based on AND, for example cityu AND dateu.
If so, here's a giant refactor. Just as a note, there may be some JavaScript errors because I had no way of testing this. But the code is fairly simple and straightforward:
var lst = [] // I'm not using these.
var lst2 = []
var lst3 = []
alert(cityu);
alert(dateu);
alert(numberu);
var getActiveFilters = function() {
// Edit possibleFilters as necessary.
// the key should reflect the header of the column
// and the value is a variable referring to the user-inputted string
var possibleFilters = {
'date': dateu,
'city': cityu,
'number': numberu
};
var activeFilters = {};
for (key in possibleFilters) {
if (possibleFilters[key].length > 0) {
activeFilters[key] = possibleFilters[key];
}
}
return activeFilters;
}
// just made this into a function to get it out of the callback
var functionAfterCsv = function(rows) {
var activeFilters = getActiveFilters();
var filteredList = [];
var addRow = false;
for(i = 0; i < rows.length; i++) {
// see if the current row matches all the filters present
for (key in activeFilters) {
if (rows[i][key] === activeFilters[key]) {
addRow = true;
} else {
addRow = false;
// if the row doesn't meet one of the conditions,
// there's no need to check the rest
break;
}
}
if (addRow) {
filteredList.push(row[i]);
}
}
return filteredList;
};
d3.csv("kyle.csv", function (d) {
return {
city: d.from,
number: d.phone_number,
date: d.from_date
};
}, function (error, rows) {
functionAfterCsv(rows);
})
});
If you're filtering using OR, then you'll need to change your comparison to something like this:
for (key in activeFilters) {
if (rows[i][key] === activeFilters[key]) {
addRow = true;
break; // if one is true, that's good enough for an OR
} else {
addRow = addRow || false;
}
}
if (addRow) {
filteredList.push(row[i]);
// reset addRow for the next row
addRow = false;
}
Hope this was closer to your intended logic!