I am trying to combine the ng-class condition statements in my case.
I have the following statements.
<div ng-class="item.new ? 'newItem' : 'oldItem'; 'discount' : item.getType === true && item.getSave === true">{{item.name}}</div>
I am getting the parsing error.
Syntax Error: Token ':' is an unexpected
I am not sure how to fix this. Can anyone help me about it? Thanks a lot
Use this syntax instead:
<div ng-class="{newItem: item.new, oldItem: !item.new, discount: item.getType === true && item.getSave === true}">
Or alternatively put your logic in a function:
<div ng-class="getClasses(item)">
And in your controller:
$scope.getClasses = function(item) {
return {
newItem: item.new,
oldItem: !item.new,
discount: item.getType === true && item.getSave === true
};
}
FYI: from that function you can return an object, or an array of classes, or a string.
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 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>
using
var states = {
Abbreviation: "AR",
Name: "Arkansas"
}
Why will this work.
$.each(states, function () {
var o = {
value: this.Abbreviation,
text: this.Name
}
if (this.Abbreviation === "AR") { //hardcoded for you pleasure
o.selected = 'selected';
}
e.append(
$('<option/>', o)
);
});
But not this:
$.each(states, function () {
e.append(
$('<option/>', {
value: this.Abbreviation,
text: this.Name,
selected: (this.Abbreviation === csc.statesDDL.txt().val() ? 'selected' : '')
})
);
});
Are there restrictions to .append within jquery for ternary :? operators?
Notes: I have a logged the output of the if statements, when running the commented out code it shows ALL options as selected, the the logs output only 1 options = true. The uncommitted out code, behaves as expected.
It's not the ternary that's the issue, it appears to be how jQuery/HTML is handling the empty string. jQuery is most likely not resolving the property to an explicit false and thus creating an element with a "selected=''" which the browser may just be interpreting as "selected" which I believe is from an old HTML standard that recognized that as being selected. If you make the false explicit it will work:
selected: (this.Abbreviation === csc.statesDDL.txt().val() ? 'selected' : false)
I'm guessing it is not evaluating it as
((this.Abbreviation === csc.statesDDL.txt().val()) ? 'selected' : '')
but is evaluating it as
(this.Abbreviation === (csc.statesDDL.txt().val() ? 'selected' : ''))
I have an array of objects in AngularJS like this:
var example = [ {id:'1',
read: false,
folder: 'inbox'},
{id:'2',
read: true,
folder: 'inbox'},
{id:'3',
read: true,
folder: 'trash'},
{id:'4',
read: false,
folder: 'trash'}];
And I need to delete any object that has the attributes folder == 'trash' and read == true at the same time.
So I tried to do it like this with lodash:
example = lodash.filter(example, function(value, index) {
return (value.folder !== 'trash') && (value.read !== true);
});
It should delete only the item #3, but it deletes #3 and #4.
Obviously I'm not understanding how lodash.filter really works.
Can someone please help?
You logical operator is not correct. set the condition to folder == 'trash' and read == true and the negate it.
example = lodash.filter(example, function(value) {
return (value.folder == 'trash' && value.read == true) == false;
});
You need to remove the quotes around 'true'. You want to keep all the elements where the folder is not 'trash' or the read property is not true so your logic would look like this
return (value.folder !== 'trash') || (value.read !== true);
The operator !== is false. use == instead.
return (value.folder == 'trash' && value.read == 'true') == false;