navigator.language not recognized correctly in app.js - javascript

This is my controller
app.controller('languagesCtrl', function($scope) {
var lang = window.navigator.language || window.navigator.userLanguage;
if (lang === 'it' || 'it-it' || 'it-IT') {
$scope.showcase = 'Vetrina';
$scope.products = 'Prodotti';
$scope.cta = 'Nuova collezione strumenti';
} else {
$scope.showcase = 'Showcase';
$scope.products = 'Products';
$scope.cta = 'Check out new products!';
}
});
and even if I'm SURE my navigator.language isn't 'it-IT' (checked here), my angular-based website doesn't use what's inside in the else's brackets.

Your expression is always going to be true, the way you have || operator used.
When expression evaluated
1st part (lang === 'it') it might be true or false, suppose it is false.
then expression becomes like (false || 'it-it' || 'it-IT') which will always return going to return next expression value, here it would be it-it in this case, so anyways if condition is going to get satisfied.
Change it to below.
if (lang === 'it' || lang === 'it-it' || lang === 'it-IT')
OR event simplified.
if (['it','it-it','it-IT'].indexOf(lang) > -1)

ES6 solves this beautifully
I am just putting this here incase people in future stumble upon this. Use includes() for ES6.
['it','it-it','it-IT'].includes(language)
ES5 Solution
This stuff always used to get me, until I realised, I am using multiple OR comparisons incorrectly. So I did this to make it more readable.
Array.prototype.contains = function(obj) {
return this.indexOf(obj) > -1;
};
Now, you can use it like this:
var language = $window.navigator.language.
if (['it','it-it','it-IT']].contains(language)) {
alert('yes');
}
This is more readable. Of course, if you are using underscore.js, they have the following helper.
_.contains([], search)

Related

Need to improve JS function using a few || (logical or) or mayby another solution

I have function it works good but I want to improve that
const canPrepareReview = (): boolean => {
if (loading) return true;
if (Object.keys(assets).length !== 0) return true;
return master;
}
<Button
disabled={!canPrepareReview()}
>
I try to use something like this
<Button
disabled={loading || master || Object.keys(assetsSelected).length === 0}
>
but it does not work So any ideas on how it can be improved?
The function evaluates:
loading || Object.keys(assets).length !== 0 || master
But in the first disabled attribute, the function result is negated, so we evaluate:
!(loading || Object.keys(assets).length !== 0 || master)
If you put that as expression in the disabled attribute, it should give equivalent behaviour as in the function-based solution.
However, defining the function is actually better practice. Don't bloat attributes with complex expressions.

How to remove my nested ternary expressions in my code?

I would like to clean up my code but I can't. I would like to get rid of the nested ternary expressions. I work with react js 17.0.2. Do you have any ideas to help me?
const buildNewFilters = (query, filtersIndex: Array<string>) => {
const newFilters = {};
for (let i = 0; i < filtersIndex.length; i++) {
newFilters[filtersIndex[i]] = router.query[filtersIndex[i]] ? typeof router.query[filtersIndex[i]] == ('string' || 'number') ? [router.query[filtersIndex[i]]] : router.query[filtersIndex[i]] : undefined
if (filtersIndex[i] === 'designers' && newFilters.designers) {
newFilters.designers = newFilters.designers.map(designer => parseInt(designer));
}
}
return newFilters;
};
if (router.query[filtersIndex[i]]) {
if (typeof router.query[filtersIndex[i]] == ("string" || "number")) {
newFilters[filtersIndex[i]] = [router.query[filtersIndex[i]]];
} else {
newFilters[filtersIndex[i]] = router.query[filtersIndex[i]];
}
} else {
newFilters[filtersIndex[i]] = undefined;
}
If you are not used to working with ternary operators, I understand that it's not easy to refactor the code. First, you can read about what ternary expressions are and try them out in the Mozilla Documentation about ternary operators. Basically the part of the code before the ? evaluates to either true or false and if it evaluates to true, the part before the subsequent : is executed (in your case assigned to the variable newFilters[filtersIndex[i]], otherwise the part after the : will be assigned to the variable.
My tip would be to put the line you want to refactor in a text editor to experiment with it, and add line breaks and/or tabs after the ? and : signs to see the structure better and to see what is happening at each step.

Javascript dynamic conditioning

I want to build a IF condition which is built dynamically based on the parameters it gets. More over, this is expected to be built as a plugin.
For instance, there are 3 parameters for student object, called age,name, phone_numbers. Also, there is a option object for selection parameters.
In the condition,
if(student.age >option.age & student.name == option.name & student.phonenumbers == option.phonenumbers ){
// do stuff
}
If any parameter is missing, it should not be included in the condition. For example, assume, in case option.name is undefined, then the if condition should be prepared as following,
if(student.age >option.age & student.phonenumbers == option.phonenumbers ){
// do stuff
}
Moreover, why this kind of thing is required is, here an array of (500 objects) students objects are iterated. The above condition can be splitted into seperat conditions, but then the iteration will be multipled by the number of conditions !!!. So I m looking for a way to add all conditions into one.
However, my approach is, create the expression as a string and then execute it with eval(..),but as far as I know that using eval can lead vulnerabilities.
Any one let me know a way to implement a dynamic conditions.
Note that the JavaScript and operator is &&.
For your example, this should work:
if((!student.age || student.age>option.age) &&
(!student.name || student.name==option.name) &&
(!student.phonenumbers || student.phonenumbers==option.phonenumbers)
) {
}
How about
function testStudent(student,option) {
var res = [];
var test = true;
if (student.age) res.push(student.age > option.age);
if (student.name) res.push(student.name == option.name);
if (student.phonenumbers) res.push(student.phonenumbers == option.phonenumbers);
for (var i=0;i<res.length;i++) {
test = test && res[i];
}
if (res.length > 0 && test) {
//do stuff
}
}
generic:
function testObjects(obj1,obj2) {
for (var o in obj1) { // assuming obj2 is a superset of obj1
if (o === "age" && obj1.age <= obj2.age) return false;
if (obj1.hasOwnProperty(o) && obj1[o] != obj2[o]) return false;
}
return true;
}
var ok = testObjects(student,option);
You can have your conditions in functions and those functions in an Array. so then you can do a loop in the Array and call every function (condition).
var aConds = [];
function firstCond(params) {return (params<0)};
function secondCond(params) {return(params!='hi')};
aConds.push(firstCond);
...
for(var i=0;i<aConds.length;i++)
{
if(!aConds[i](params)) console.log("a condition has not been meet");
}
Would it work to allow undefined in each condition?
if((student.age == undefined || student.age > option.age) && (student.name == undefined || student.name == option.name) ...

Is there any way of determining which or statement is true in javascript?

So say I have an if statement:
if(a=='' || b==''){
//which is true?
}
Is it possible to determine which statement satisfied the if statement without doing a switch statement or another if statement to check?
You can define a token to store what condition was true:
var token = null;
if ((a == '' && (token = 'a')) || (b == '' && (token = 'b'))) {
// Here token has an 'a' or a 'b'. You can use numbers instead of letters
}
I think it's the simplest way to do what you want.
As others have said, you have to test the conditions separately, but you can kind of mix worlds.
var test1 = 1 == 1; // true
var test2 = 2 == 1; // false
if (test1 || test2) {
// If either conditions is true, we end up here.
// Do the common stuff
if (test1) {
// Handle test1 true
}
if (test2) {
// Handle test2 true
}
}
No, you have asked explicitly if one or both are true. There's no way to work out which of those sub-expressions is true without another conditional of some sort.
If you're interested in different behaviour based on which is true, you should probably separate them with a possibly-common bit, something like
either = false;
if (a == ' ') {
doActionsForA();
either = true;
}
if (b == ' ') {
doActionsForB();
either = true;
}
if (either) {
doActionsForAorB();
}
If you care about which of the two conditions is true the only way to find out is to test them separately, e.g.
if(a==''){
// ...
}
else if(b=='') {
// ...
}
Sometimes, especially in more complicated conditionals, it helps if you store the result of each condition and reuse it later on:
var isFoo = a == '';
var isBar = b == '';
// You can now use isFoo and isBar whenever it's convenient
the simple solution:
if ((ia=(a=='')) || (b=='')) {
// ia indicate whether the boolean expression a have been true.
// ia -> a has been true, b may have, !ia -> b has been true, a has not
}
there is no ib in the simple solution as it won't be always be set due to shortcut evaluation.
to cater for shortcut evaluation try:
if (((ia=(a=='') || (ib=(b=='')) && ((ib=(b=='')) || (ia=(a==''))) {
// ia, ib indicate whether the corresponding boolean expressions have been true
}
if(a=='' || b==''){
var x= a || b;
//if a is ''(falsy) x will be b, else a
}
var phone="";
var email="something";
if(phone=='' || email==''){
var x= (phone) ? 'phone':'email';
console.log(x); //email
}

Simpler way to format if statement?

I have an if statement:
if(firstString == "no" && secondString == "no" && thirdString == "no"){
// Do stuff here
}
Is there a prettier way to format this? Using false instead of "no" is not an option, since the data I'm checking is from an AJAX request and I don't control its output. Otherwise I'd write it this way:
if(!firstString && !secondString && !thirdString){
// Do stuff here
}
Thanks
UPDATE:
I know this is totally ridiculous, but it occurred to me that this might actually be the shortest way:
if(firstString + secondString + thirdString == "nonono"){
// Do stuff here
}
Given that the number of strings is known in advance, then you have 2 options as far as I can see..
Leave it as it is. The if statement isn't hard to read, and any alternate formats will either be as complicated or more complicated.
convert the strings to booleans when you retrieve the data from the AJAX request, so that you're storing TRUE or FALSE instead of "yes" and "no". That would allow you to use a your preferred if statement format, and might be more efficient than many string comparisons if you do a lot of them.
In the end, which you do is up to you, but personally I think it would be better to just stick with what you've got. Don't worry about formatting an if statement, it's pretty obvious what it does, and in my opinion doesn't need to change.
If( "no" == firstString && firstString == secondString && secondString == thirdString )
It was a little difficult to determine exactly what you are evaluating to true or false, but this can be tweaked a tad to get what you're looking for.
var checkStrings = function() {
var no = "no",
args = Array.prototype.slice.call(arguments);
for (var i = 0, len = args.length; i < len; i++) {
if (args[i] !== no) {
return false;
}
}
return true;
};
if (checkStrings(firstString, secondString, thirdString)) {
// Do stuff here
}
Sorry, wasn't thinking--this is if you were checking whether ANY were 'no'
if ($.inArray('no', [firstString, secondString, thirdString]) >= 0) {
// Do something if the value is 'no'
}
UPDATED ANSWER
Unfortunately, jQuery doesn't have the reduce() function (another Array extra introduced in JS 1.6, but not available in older browsers) which would do the trick nicely.
Here's one way to check if all are 'no':
var found = true;
$.each([firstString, secondString, thirdString], function (i, str) {
if (str !== 'no') {
found = false;
}
});
It may seem uglier, but it should be shorter if you have a lot more strings to check.
If you want it wrapped in a function you could do:
function allTrue (arr, checkStr) {
var found = true;
$.each(arr, function (i, str) {
if (str !== checkStr) {
found = false;
}
});
return found;
}
if (allTrue([firstString, secondString, thirdString], 'no')) {
// ...
}
function F(var value){
return value === "no";
}
if(F(firstString) && F(secondString) && F(thirdString)){
// Do stuff here
}
Another option, using jQuery.unique:
var uniques = $.unique([firstString, secondString, thirdString]);
if (uniques.length === 1 && uniques[0] === "no") {
// do stuff
}

Categories

Resources