I have this little snippet of code
<Calendar
style={{ height: 600, width: "120%" }}
eventPropGetter={(event, start, end, isSelected) => {
var backgroundColor = "#000000";
console.log(event.estado);
console.log(isSelected);
if (event.estado === 0 && isSelected === false)
console.log("here");
if (event.estado === 0 && isSelected === true)
backgroundColor = "#4d4dff";
if (event.estado === 2 && isSelected === true)
backgroundColor = "#ff8c1a";
if (event.estado === 2 && isSelected === false)
backgroundColor = "#b35900";
return { style: { backgroundColor } };
}}
console.log(event.estado) spits out 0
console.log(isSelected) spits out false
however, console.log("here") is never triggered. As I'm new to JS, I'm assuming there's some quirkiness in how JS evaluates truthiness that I'm not aware about
Any help would be appreciated
The 0 was in fact "0", that's why it was evalutaing wrong
As per html doc below, type and value should be same. Please check whether type of isSelected is same.
When using the === operator, equal booleans are not equal, because the === operator expects equality in both type and value
I tried the snippet on my end and it worked for me perfectly and is printing here (I didn't use console log though). Can you once try to equate estado to 1 and check if the background changes!!
Related
I having this condition on a form group:
if((age>17 && (this.frType=="Infant"))
|| (age>40 && this.frType=="Grandchild")
|| (age<=5 &&
(this.frType!="Child"
|| this.frType!="Infant"
|| this.frType!="Grandchild" || this.frType!="Cousin")))
It contain 3 main conditions:
If a person aged 17, cannot be set to infant
If a person is bigger than 40, he cannot be a grandchild
If a person is less than 5 years, he should be child, infant, grandchild or cousin.
If one of these conditions is true, I will send an error message.
The error I am receiving is:
[ts] This condition will always return 'true' since the types
'"Child"' and '"Infant"' have no overlap. [2367]
On this part of the if condition`:
|| this.frType!="Infant" || this.frType!="Grandchild" || this.frType!="Cousin")))
I am using the exact condition in a different component, and it does not show an error.
if((age>17 && (this.family_relation_type=="Infant"))
|| (age>40 && this.family_relation_type=="Grandchild")
|| (age<=5 &&
(this.family_relation_type!="Child" ||
this.family_relation_type!="Infant" ||
this.family_relation_type!="Grandchild" ||
this.family_relation_type!="Cousin")))
Here is how I am calculating the age in both components:
let timeDiff = Math.abs(Date.now() - this.formGroup.controls['dob'].value);
let age = Math.floor((timeDiff / (1000 * 3600 * 24))/365);
Consider the standalone expression:
(this.frType!="Child" || this.frType!="Infant")
If frType is Child, the second part will be true, so the expression will evaluate to true. If frType is Infant, then the first part will be true, so the expression will evaluate to true. If frType is neither Child nor Infant, then the first part will be true, and the expression will, again, evalute to true - the logic is faulty, it'll always resolve to true.
(If you add additional || conditions for Grandchild and Cousin, the same thing keeps happening - it'll always resolve to true)
Either use && instead:
|| (age<=5 && (
this.frType!="Child"
&& this.frType!="Infant"
&& this.frType!="Grandchild"
&& this.frType!="Cousin"
))
Or, to make the logic easier to follow, you might consider using an array, and use .includes:
const kidsFiveAndUnder = ['Child', 'Infant', 'Grandchild', 'Cousin'];
// ...
|| (age <= 5 && !kidsFiveAndUnder.includes(this.frType))
Maybe i can help someone with this.
In my case the error was triggered by:
*ngIf="fooArray.length === 0"
so i modified it to be:
*ngIf="fooArray.length < 1"
Makes no sense to me, but it works.
I struggled with this problem recently. Sharing my experience here
Basically IDE does not allow to compare an object.enum with a string. As a solution, a method in the component.ts is added to compare the enum
Details :
export enum Status {
NEW,
PROGRESS,
FINISHED
}
export interface Model {
id : number;
name : string;
status : Status
}
Now in the component.html, I was trying to compare the model status
<div *ngFor="let m of modelItems" >
<i *ngIf="m.status === 'NEW'" class="icon-new"></i>
</div>
Error : This condition will always return 'false' since the types 'Status' and 'string' have no overlap.ngtsc(2367)
I also tried defining the status enum in the component.ts and used that for comparison
public StatusEnum = Status;
<div *ngFor="let m of modelItems" >
<i *ngIf="StatusEnum[m.status] === 'NEW'"
class="icon-new"></i>
</div>
With the above solution, there is no IDE error, but the condition never true, as the enum[value] give a numeric value.
The next option I tried was as follows
<div *ngFor="let m of modelItems" >
<i *ngIf="m.status=== StatusEnum[StatusEnum.NEW]" class="icon-new"></i>
</div>
But ended up with the error again in the IDE
Error : This condition will always return 'false' since the types 'Status' and 'string' have no overlap.ngtsc(2367)
Finally what solved the issue it implement a method in the component.ts
Solution
component.ts
public StatusEnum = Status; //To refer in the HTML
checkStatus(m: Model, status: Status): boolean {
return Status[m.status] as unknown === status;
}
Note : Status[m.status] as unknown
HTML
<div *ngFor="let m of modelItems" >
<i *ngIf="checkStatus(m,StatusEnum.NEW)"
class="icon-new"></i>
</div>
Define the data types of all your variables explicitly.
For example, this code has the same error mentioned in the thread title and I fixed by defining the data types of the variables explicitly.
From:
const selectedLangCulture = "en"; // or "ar-SA"
const direction = "rtl";
const languageChanged =
(direction === "rtl" && selectedLangCulture === "en") ||
(direction === "ltr" && selectedLangCulture === "ar-SA");
To:
const selectedLangCulture: string = "en"; // Put the datatype string.
const direction: string = "rtl"; // Put the datatype string.
const languageChanged =
(direction === "rtl" && selectedLangCulture === "en") ||
(direction === "ltr" && selectedLangCulture === "ar-SA");
In my case, I was using a type named type for the button element with React.ComponentPropsWithRef<'button'>
type ButtonProps = {
type?: 'submit' | 'button' | 'link'; // ❌
} & React.ComponentPropsWithRef<'button'>;
the type was overridden because React.ComponentPropsWithRef<'button'> had a type in it also. I replaced it with elementType and the problem is solved.
type ButtonProps = {
elementType?: 'submit' | 'button' | 'link'; // ✅
} & React.ComponentPropsWithRef<'button'>;
In my case, I simply had to rebuild my app because the type definitions got briefly out of sync.
I have this code in React Js but the flagImg is equal with the 2nd value (GRFlag). I think that is the way that I am trying to compare the 2 strings to the problem. Does anyone help?
const [lan ,setLan] = React.useState("GR");
const flagImg = {lan} === "GR" ? <UKFlag style={{width: "40px"}}/> : <GRFlag style={{width: "40px"}}/>;
const [lan ,setLan] = React.useState("GR");
const flagImg = (lan === "GR" ? <UKFlag style={{width: "40px"}}/> : <GRFlag style={{width: "40px"}}/>);
You compare an object with a string here, it is always false
{lan} === 'GR'
This is what you need
lan === 'GR'
So
{lan} === "GR"
Will actually compare an object with a key lan to a string 'GR' and that would result in false right because it's actually comparing {lan: 'GR'} === 'GR' . Remove those {} brackets and that should solve it for you.
lan === 'GR'
I have 2 user IDs and I would like to do different but very similar logic if I have only one or both. Is there a way to consolidate this code, as right now it looks ugly.
function getUserPermission(primaryId, secondaryId, role) {
let permission = userInfo.permissionList.filter( permission => {
//logical AND
if(primaryId && secondaryId){
// have both IDs, use both IDs
(permission.primaryId === primaryId && permission.secondaryId === secondaryId) && permission.role === role
}
//logical XOR
else if((primaryId && !secondaryId) || (!primaryId && secondaryId)) {
// have only 1 ID, use 1 ID
(permission.primaryId === primaryId || permission.secondaryId === secondaryId) && permission.role === role
}
})[0]
return permission
}
First, it seems like this logic doesn't handle when both ids are invalid. You'll want to handle that somehow (looks like both the other answers so far include something along those lines).
Next, since you're only returning the first matching permission, I would suggest using a solution that doesn't keep looping once you've found that first match. In that respect, Array.find() is far better than Array.filter() for this use case.
If I were to put the other answers together, it would be something like this:
function getUserPermission(primaryId, secondaryId, role) {
if (!primaryId && !secondaryId) return null // at least one must be populated, why loop at all?
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!primaryId || primaryId === permission.primaryId) // if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId) // if secondary is populated, it needs to match
);
}
...but that doesn't handle the case where a perfectly valid ID happens to be 0. That could depend on your data, though. Perhaps you're always using string-based IDs, for example. It also checks for valid ids on every loop (something you may or may not be perfectly comfortable with)
With those potential issues in mind, I made some assumptions about your data/types and threw a more unorthodox approach together in an attempt to solve them:
const getUserPermission = (primaryId = -1, secondaryId = -1, role = '') => {
if (primaryId < 0 && secondaryId < 0) return null
const conditions = [ p => p.role === role ]
.concat(primaryId >= 0 ? [ p => p.primaryId === primaryId ] : [])
.concat(secondaryId >= 0 ? [ p => p.secondaryId === secondaryId ] : [])
return userInfo.permissionList.find(p => conditions.every(fn => fn(p)))
}
...this last one makes an array of functions, conditions, to check each permission against. The first one to match every condition should be returned (in theory, at least - I didn't test it)
What about something like this?
if(!primaryId && !secondaryId) {
throw Error("No ID was provided");
}
let permission = userInfo.permissionList.filter(p => p.role === role);
if(primaryId) {
permission = permission.filter(p => p.primaryId === primaryId);
}
if(secondaryId) {
permission = permission.filter(p => p.secondaryId === secondaryId);
}
return permission[0];
function getUserPermission(primaryId, secondaryId, role) {
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!!primaryId || !!secondaryId)// at least one is populated
&& (!primaryId || primaryId === permission.primaryId)// if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId)// if secondary is populated, it needs to match
);
}
This is slightly different from your code in that if there is no match, it returns null, whereas yours throws an exception. If you mean to throw, you can always put the result in a variable and check for null.
What about this refactoring :
function getUserPermission(primaryId = undefined,secondaryId = undefined,role) {
primaryId === undefined && secondaryId === undefined && throw new Error("Ids are required");
const userPermission = userInfo.permissionList
.filter((permission) => role && permission.role === role)
.filter((permission) => primaryId && permission.primaryId === primaryId)
.filter(
(permission) => secondaryId && permission.secondaryId === secondaryId
);
return userPermission[0];
}
I having this condition on a form group:
if((age>17 && (this.frType=="Infant"))
|| (age>40 && this.frType=="Grandchild")
|| (age<=5 &&
(this.frType!="Child"
|| this.frType!="Infant"
|| this.frType!="Grandchild" || this.frType!="Cousin")))
It contain 3 main conditions:
If a person aged 17, cannot be set to infant
If a person is bigger than 40, he cannot be a grandchild
If a person is less than 5 years, he should be child, infant, grandchild or cousin.
If one of these conditions is true, I will send an error message.
The error I am receiving is:
[ts] This condition will always return 'true' since the types
'"Child"' and '"Infant"' have no overlap. [2367]
On this part of the if condition`:
|| this.frType!="Infant" || this.frType!="Grandchild" || this.frType!="Cousin")))
I am using the exact condition in a different component, and it does not show an error.
if((age>17 && (this.family_relation_type=="Infant"))
|| (age>40 && this.family_relation_type=="Grandchild")
|| (age<=5 &&
(this.family_relation_type!="Child" ||
this.family_relation_type!="Infant" ||
this.family_relation_type!="Grandchild" ||
this.family_relation_type!="Cousin")))
Here is how I am calculating the age in both components:
let timeDiff = Math.abs(Date.now() - this.formGroup.controls['dob'].value);
let age = Math.floor((timeDiff / (1000 * 3600 * 24))/365);
Consider the standalone expression:
(this.frType!="Child" || this.frType!="Infant")
If frType is Child, the second part will be true, so the expression will evaluate to true. If frType is Infant, then the first part will be true, so the expression will evaluate to true. If frType is neither Child nor Infant, then the first part will be true, and the expression will, again, evalute to true - the logic is faulty, it'll always resolve to true.
(If you add additional || conditions for Grandchild and Cousin, the same thing keeps happening - it'll always resolve to true)
Either use && instead:
|| (age<=5 && (
this.frType!="Child"
&& this.frType!="Infant"
&& this.frType!="Grandchild"
&& this.frType!="Cousin"
))
Or, to make the logic easier to follow, you might consider using an array, and use .includes:
const kidsFiveAndUnder = ['Child', 'Infant', 'Grandchild', 'Cousin'];
// ...
|| (age <= 5 && !kidsFiveAndUnder.includes(this.frType))
Maybe i can help someone with this.
In my case the error was triggered by:
*ngIf="fooArray.length === 0"
so i modified it to be:
*ngIf="fooArray.length < 1"
Makes no sense to me, but it works.
I struggled with this problem recently. Sharing my experience here
Basically IDE does not allow to compare an object.enum with a string. As a solution, a method in the component.ts is added to compare the enum
Details :
export enum Status {
NEW,
PROGRESS,
FINISHED
}
export interface Model {
id : number;
name : string;
status : Status
}
Now in the component.html, I was trying to compare the model status
<div *ngFor="let m of modelItems" >
<i *ngIf="m.status === 'NEW'" class="icon-new"></i>
</div>
Error : This condition will always return 'false' since the types 'Status' and 'string' have no overlap.ngtsc(2367)
I also tried defining the status enum in the component.ts and used that for comparison
public StatusEnum = Status;
<div *ngFor="let m of modelItems" >
<i *ngIf="StatusEnum[m.status] === 'NEW'"
class="icon-new"></i>
</div>
With the above solution, there is no IDE error, but the condition never true, as the enum[value] give a numeric value.
The next option I tried was as follows
<div *ngFor="let m of modelItems" >
<i *ngIf="m.status=== StatusEnum[StatusEnum.NEW]" class="icon-new"></i>
</div>
But ended up with the error again in the IDE
Error : This condition will always return 'false' since the types 'Status' and 'string' have no overlap.ngtsc(2367)
Finally what solved the issue it implement a method in the component.ts
Solution
component.ts
public StatusEnum = Status; //To refer in the HTML
checkStatus(m: Model, status: Status): boolean {
return Status[m.status] as unknown === status;
}
Note : Status[m.status] as unknown
HTML
<div *ngFor="let m of modelItems" >
<i *ngIf="checkStatus(m,StatusEnum.NEW)"
class="icon-new"></i>
</div>
Define the data types of all your variables explicitly.
For example, this code has the same error mentioned in the thread title and I fixed by defining the data types of the variables explicitly.
From:
const selectedLangCulture = "en"; // or "ar-SA"
const direction = "rtl";
const languageChanged =
(direction === "rtl" && selectedLangCulture === "en") ||
(direction === "ltr" && selectedLangCulture === "ar-SA");
To:
const selectedLangCulture: string = "en"; // Put the datatype string.
const direction: string = "rtl"; // Put the datatype string.
const languageChanged =
(direction === "rtl" && selectedLangCulture === "en") ||
(direction === "ltr" && selectedLangCulture === "ar-SA");
In my case, I was using a type named type for the button element with React.ComponentPropsWithRef<'button'>
type ButtonProps = {
type?: 'submit' | 'button' | 'link'; // ❌
} & React.ComponentPropsWithRef<'button'>;
the type was overridden because React.ComponentPropsWithRef<'button'> had a type in it also. I replaced it with elementType and the problem is solved.
type ButtonProps = {
elementType?: 'submit' | 'button' | 'link'; // ✅
} & React.ComponentPropsWithRef<'button'>;
In my case, I simply had to rebuild my app because the type definitions got briefly out of sync.
<div style={{'backgroundColor': status === 'approved' ? 'blue' : 'black'}}>
</div>
black is the default color but what if I want to add the 3rd condition?
status can be 'approved', 'rejected', 'pending' or more.
You could do the following:
<div style={{'backgroundColor': status === 'approved' ? 'blue' : status === 'pending' ? 'black' : 'red'}}>
</div>
This means if status === 'approved' set the background color as blue, if status === 'pending' set it as black, else set it as red.
I would suggest using functions if your conditions get complicated, to not degrade your code readability.
getBackgroundColor(status) {
if (status === 'approved') {
return 'blue';
}
if (status === 'pending') {
return 'red';
}
return 'black';
}
render() {
// ...
return (
<div style={{ 'backgroundColor': this.getBackgroundColor(status) }}></div>
);
}
To chain ternary operations you need to add another ternary operator to be returned when the conditions are not met, for example:
a === true ? a : b
In place of b you would add a new ternary operator, like so:
a === true ? a : b === true ? b : c
Bonus:
When you're just checking for null/undefined/false you can use the pipe operator, for example this:
var x = a !== null ? a : b;
Can be simplified to:
var x = a || b;
And pipe operators can be chained infinitely like ternary operators.
There is another way how to do it with the a bit more readable & cleaner code style. We can replace the ternary operator with the object literal and use this instead of nesting ternary operators, like so
function getBackgroundColor(status){
const backgroundColorByStatus = {
approved: 'blue',
pending: 'black',
default: 'red',
}
return backgroundColorByStatus[status] || backgroundColorByStatus['default']
}
// somewhere below
<div style={{'backgroundColor': getBackgroundColor(status)}}>fancy div</div>
With this approach you can have multiple colors and code will be still clean & readable :)
Hope it will help.
Multiple condition in ternary operator in JSX and JS
style={{'backgroundColor': status === 'approved' ? 'blue' : status === 'cancel' ? 'red' : 'green'}}
Using multiple ternary operators is not a good idea, better to use a function and put if-else conditions inside that and call that function from render. It helps you to make the render part clean and short.
Like this:
<div style={{'backgroundColor': this._style(status)}}></div>
_style(status){
if(status == 'approved')
return 'blue';
else if(status == 'pending')
return 'black';
else return 'red';
}
I'd handle it separately as other types of status may appear in the future.
const getBackgroundColor(status) {
if (status === 'approved') {
return 'blue'
}
else if (status === 'pending') {
return 'black'
} else {
return 'red'
}
}
<div style={{'backgroundColor': getBackgroundColor(status) }}>
</div>
Code gets easier to understand and reason about.
I would not use ternary because it gets hard to read. Why not store the status and associated colors in an object then just reference that?
const colors = {approved:"blue", rejected:"red"};
<div style={{'backgroundColor':status in colors ? colors[status] : "black"}}>
</div>
Oops, I didn't realize how old this thread was.
Inside render you can create an empty array variable. As shown below, you can apply nested styling. Also, you won't need a nested ternary operator.
let styleValue = [];
if(status === 'approved') {
styleValue.push({backgroundColor:'blue'})
} else {
styleValue.push({backgroundColor:'black'})
}
<div style={styleValue}>
</div>