Error comparing Array elements in Google script - javascript

I have a problem in one of my scripts for a Google Spreadsheet.
In the script I create two arrays, the first one contains a column from the sheet:
var sheet_data = sheet.getRange('C1:C').getValues(); // for example sheet_data = [[""],["text1"],["text2"],[""],["text3"]]
and the second one is hard-coded:
var sheet_names = [["text1"],["text2"],["text3"]];
The sheet_data contains all elements present in sheet_names and I have a while function that finds one specific element (say text1) in sheet_data:
i = 0;
while (sheet_data[i] != sheet_names[1]) { i++; }
In short, I want to find the cell in the column C that contains a specific string. However the loop containing this condition doesn't work for some reason. The loop keeps going on and on but i never increases. I tried the same with a for loop containing an if statement but the if statement containing the above condition fails too. I assumed there must be something wrong with the condition but if I explicitly check the array elements that should be the same, it works:
if (sheet_data[i] == "text1" && sheet_names[1] == "text1") // this works
Why doesn't the direct comparison of the two array elments work?

This looks more to me as a JavaScript issue (I am not familiar with Google Script flavor but the same logic should apply)
You are trying to sheet_data[i] != sheet_names[1], where both sheet_data[i] and sheet_names[1] are ['text1']. In JS, these are 2 different array objects (not same reference), so they would never equal to each other. (different from Python)
The reason that your second solution works is even tricker: when you do ['test1'] == 'test1', because the 2 elements are of different types, JavaScript will try to convert them to the same type, due to your use of == instead of ===. ['test1']'s stringified version is exactly 'test1', resulting in your second solution working.
See example below:
console.log([] == []) // false, different object reference
console.log(['test'] == ['test']) // false
console.log('test' == 'test') // true, both are primitive
console.log(['test'].toString()) // 'test'
console.log(['test'] == 'test') // true, ['test'] converted to 'test' due to ==
console.log(['test'] === 'test') // false, strict comparison without type conversion
// More amazing JS tricks!
console.log([] == 0) // true
console.log([] == '') // true
console.log('' == 0) // true
console.log('' == false) // true
console.log(false == 0) // true
console.log([] == false) // true
// OOOPS...
console.log({} != true) // true
console.log({} != false) // true
// as you see here, NEVER USE == ! use === instead

Related

Object does not equal to true or false

So my uploaded media file (event.target.files[0]) does not equal to true or false.
It has a typeof object.
It's part of some form state and I'd like to check the object whether all fields are not empty "".
I thought a JS object should always === true, but maybe this is different for 'files' objects?
=== checks for strict equality, so the two values must be exactly the same.
An object is truthy, but does not equal true, so what you are really doing is { ... } === true, which is false.
If you want to check if none of the object's values are empty, you can filter for empty values:
const empty = Object.keys(theObject).length === 0 || Object.values(theObject).filter(value => {
return value.trim() === '';
}).length > 0;
=== tests for equal value and equal type (ref). typeof(true) is boolean but a file is not a boolean. So the comparison will never yield true.
See also https://stackoverflow.com/a/8511350/4640820
To check the type of a value, you must write
if( (typeof <your value>) == ("<expected type>")){
...
}
For example, a statement like this:
if( (typeof 42)=="number" )
is true.
Reference for most cases of typeof

How do I sort my array of data on an observable?

Using angular, I'm pulling data from my API. I'm unsure about two things if someone could give me insight:
Should I be sorting the array on the Observable or the Subscriber and why?
I'm unsure how to sort my array of data based off if the values are true or false using the sort() function.
Here is what my object looks like, if any of the values after hostname come back false, or if the date on UpdatedDate is over 4 weeks, I need that object to show first. If everything is true, but the date is > 2 weeks and also < 4 weeks, I need it to come second. And if the object is completely true with a date that is less than 2 weeks old, I want it to come last. There will be about 500 of these Ipcidata objects coming through.
export interface Ipcidata {
id: Int16Array;
hostname: string;
AMStatus: boolean;
BLStatus: boolean;
FirewallRullStatus: boolean;
FirewallContentStatus: boolean;
SCCMStatus: boolean;
MSBaselineStatus: boolean;
UpdatedDate: Date;
USBStatus: boolean;
}
Here's my observable, with a sort function ready
getPciInfo(): Observable <Ipcidata[]> {
return this.httpClient.get<Ipcidata[]>('http://localhost:499/api/PCImachines').pipe(
map(results => results.sort()
)
);
}
Lastly, here's some logic I wrote that does exactly what I need to check for:
sortObjects(){
const latest_date = this.datepipe.transform(this.systemInput.UpdatedDate, 'MM-dd-yyyy');
if (latest_date > this.dateMinusTwoWeeks
&& this.systemInput.AMStatus == true
&& this.systemInput.BLStatus == true
&& this.systemInput.FirewallRullStatus == true
&& this.systemInput.FirewallContentStatus == true
&& this.systemInput.SCCMStatus == true
&& this.systemInput.MSBaselineStatus == true
&& this.systemInput.USBStatus == true
){return true }
else if(latest_date > this.dateMinusMonth && latest_date < this.dateMinusTwoWeeks
&& this.systemInput.AMStatus == true
&& this.systemInput.BLStatus == true
&& this.systemInput.FirewallRullStatus == true
&& this.systemInput.FirewallContentStatus == true
&& this.systemInput.SCCMStatus == true
&& this.systemInput.MSBaselineStatus == true
&& this.systemInput.USBStatus == true
){return 'datewarning'; }
else {return false}
}
I've tried to work this into the sort function using online resources, but I'm relatively new to all of this. Some help and a brief explanation would be much appreciated.
UPDATE:
My sort object is now sorting, but it's also updating the properties on my object. For example, it is randomly changing the values of b.USBstatus to false. I just want it to display this object first if all these flags are true. what am I doing wrong?
results.sort(function(a,b) {
if (b.AMStatus == true
&& b.BLStatus == true
&& b.FirewallRullStatus == true
&& b.FirewallContentStatus == true
&& b.SCCMStatus == true
&& b.MSBaselineStatus == true
&& b.USBStatus == true
){
return -1;
}
})));
}
Array.prototype.sort() takes compareFunction as parameter.
i.e. result.sort(sortObjects)
The logic behind compareFunction is that it should take two parameters, firstElement and secondElement, say a and b.
Then the compareFunction should look something like this,
function compare(a, b) {
if (a is less than b by some ordering criterion) {
return -1;
}
if (a is greater than b by the ordering criterion) {
return 1;
}
// a must be equal to b
return 0;
}
SOURCE - JavaScript Docs
1 - Should I be sorting the array on the Observable or the Subscriber and why?
In general I would sort as soon as possible. When your data set is used on other locations of your application where it is not sorted, then sorting within subscription is fine. Otherwise I think sorting with pipe is better. This also fits to the general approach to avoid subscriptions and use async pipe instead.
2 - I'm unsure how to sort my array of data based off if the values are true or false using the sort() function.
See Vishnudev's answer

combine multiple && conditions into 1

Is there a better way in Javascript to do null check on multiple elements I want to
a=null; b=null;....n=null;
So in total I have 14 variables set to null initially and I want to apply just one solution to all of them if they are ```null``.
if (a=== null && b=== null&& c=== null&& d=== null&& e=== null &&...&& n===null){
// set some field to false
}
is there a better way to check for null, as this may get cumbersome if we have more arrays added
Thanks!
Create a an array of arrays, iterate it using Array.every(), and do something if all item values are null:
if([a, b, c, ... n].every(a => a === null)) {
// set some field to false
}
If you're new to JS, in JS, values can be "falsey" or "truthy". if / while / for will run if the value it's supposed to evaluates to "truthy." There are few "falsey" values in JS, and the rest are considered "truthy." The false values are:
undefined
0
NaN
null
''
false
(I believe I got them all. Think of "six sins": there are six of these)
So check the following code, and what their outcomes are:
if(0) console.log('yay') // won't run
if(false) console.log('yay') // won't run
if(null) console.log('yay') // won't run
if('') console.log('yay') // won't run
if(NaN) console.log('yay') // won't run
if([]) console.log('yay') // will run
if('0') console.log('yay') // will run
This is a long winded way of saying if you want to do something based on whether array is empty or not, try the following:
let arr = [1,2,3,4]
if(arr.length){
//do stuff if array is not empty
} else {
// do stuff if array is empty
}
Now to actually solve the problem for you, do the following:
const masterArray = [a, b, c, d, ... , n];
let length = 0;
masterArray.forEach(subarr=>{
length += subarr.length;
})
//At this point, if no array had any elements, length would be 0
if(length === 0){
// do stuff
}

While Loops Syntax Errors

The course is asking me to form a while loop and I keep getting errors or infinite loops. What am I doing wrong?
var understand = true;
while(understand= true){
console.log("I'm learning while loops!");
understand = false;
}
You are using an assignment operator (=) and not an equals test (==).
Use: while(understand == true)
Or simplified: while(understand)
Update from comments:
=== means the value and the data type must be equal while == will attempt to convert them to the same type before comparison.
For example:
"3" == 3 // True (implicitly)
"3" === 3 // False because a string is not a number.
= means assignment, while == is comparison. So:
while(understand == true)
Also note that while and other branch structures, take conditions. Since this is a Boolean you can just use itself:
while(understand)
Also a note of the difference between == and === (strict comparison). The comparison == will attempt convert the two sides to the same data type before it compares the values. While strict comparison === does not, making it faster in most cases. So for example:
1 == "1" // This is true
1 === "1" // This is false

testing multiple variables in a conditional ? Dom Javascript

The code below represents the idea I am trying to achieve but when I test it doesn't work, what would be the appropriate way to test if q1 and q2 is equal to true?
function processForm() {
if(q1_valid = true && q2_valid = true){
alert("yes");
} else {
alert("no");
}
}
When you use simple = in javascript (and most C-like languages), what happens is that you assign the variable, then return the result of said assignment.
For instance, take the code a = b = true. This can be split up into a = (b = true). Now, if we only look at the part inside the parenthesis, you'll see that what it does is first set b to true, then return b. Then, outside the parenthesis it sets a to whatever b was (which ofcause is true), and returns the value of a. The value of a has nowhere to go, so it's simply dropped.
Now, if we go back to your if-test, what you end up with is basically this:
Set q1_valid to true.
return true (the value of q1_valid) to the && operator.
true is valid for && so it looks at right hand side.
Set q2_valid to true.
return true to the &&.
&& now has true on both sides. Returns true.
Test always passes. q1_valid and q2_valid will always be true after test is run.
The simple solution is to replace = with either == (equals) or === (type and value equals). Your if-check should look like one of the following:
1.
if(q1_valid == true && q2_valid == true)
2.
if(q1_valid === true && q2_valid === true)
Also, since working with booleans (values that are either true or false), the check for equality to true can be omitted altogheter. Another way to do this is simply like this:
if(q1_valid && q2_valid)
Two issues here:
You need to use two equals signs for comparison ==
The variables don't exist in the function, you would need to pass them as parameters when calling the function
function processForm(q1_valid, q2_valid) {
if(q1_valid == true && q2_valid == true){
alert("yes");
} else {
alert("no");
}
}

Categories