I have the following in Angular:
<div *ngIf="myarrayContainsEating('Chocolate')">Chocolate Is Good</div>
In my component, I have:
myarray = [{'name':'Charles', 'age':25, 'eating':'Vanilla'}, {'name':'Joseph', 'age':18, 'eating':'Banana'}]
myArrayContainsEating(food) {
let chocolateExists = false;
for(var i = 0; myarray.length; i++) {
if(myarray[i].eating == 'Chocolate') {
chocolateExists = true;
}
}
return chocolateExists;
}
The problem is, when I have a button where I hit it and make it so that Charles is eating 'Chocolate', it does not show the 'Chocolate Is Good' text I expect. Is there a way to make this work?
Some problems with your code were already mentioned in other answers. Another thing to remind you of is the way you modify the eating property: You have to make sure to replace the array with a new array, each time an entry changes. Else the Change Detector will not pick up your changes.
You could do it like this:
Template
<div *ngIf="myarrayContainsEating('Chocolate')">Chocolate Is Good</div>
<button (click)="charlesEatChoc()">Make Charles eat Chocolate</button>
TS
myarray = [{'name':'Charles', 'age':25, 'eating':'Vanilla'}, {'name':'Joseph', 'age':18, 'eating':'Banana'}]
myarrayContainsEating(food) {
return this.myarray.some(entry => entry.eating === food); // Check if any "eating" property is equal to food
}
charlesEatChoc() {
this.myarray = this.myarray.map(entry => // This returns a new array (!!!IMPORTANT!!!)
entry.name === 'Charles' // Map the entry if it matches your condition
? {...entry, eating: 'Chocolate'} // If it does, create a new one with the altered eating property
: entry // If not, return the entry itself without modification
);
}
Here is a working Stackblitz.
Calling a function inside an expression binding is not a good practice in Angular, since the Change Detector will have to rerun those methods each time there might have been a change. A cleaner way is to either hold a variable and change it accordingly (reactive apporach) or use a pipe.
Component template
<div *ngIf="myarray | containsFood:'Chocolate'">Chocolate Is Good</div>
<button (click)="charlesEatChoc()">Make Charles eat Chocolate</button>
Component TS
myarray = [{'name':'Charles', 'age':25, 'eating':'Vanilla'}, {'name':'Joseph', 'age':18, 'eating':'Banana'}]
charlesEatChoc() {
this.myarray = this.myarray.map(entry => // This returns a new array (!!!IMPORTANT!!!)
entry.name === 'Charles' // Map the entry if it matches your condition
? {...entry, eating: 'Chocolate'} // If it does, create a new one with the altered eating property
: entry // If not, return the entry itself without modification
);
}
Pipe TS
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'containsFood'
})
export class ContainsFoodPipe implements PipeTransform {
transform(value: Array<any>, food:string): boolean {
return value.some(entry => entry.eating === food); // Check if any "eating" property is equal to food
}
}
Again, another working Stackblitz.
Your final method should look like:
myArrayContainsEating(food) {
let chocolateExists = false;
for (let i = 0; i < this.myarray.length; i++) {
if (this.myarray[i].eating == food) {
chocolateExists = true;
}
}
return chocolateExists;
}
The following are the issues with your code:
Your if condition is incorrect. Change it to:
if (myarray[i].eating === food) {
...
}
You need to access the eating property of each object. Nevertheless, the myArrayContainsEating(...) will still return
false as there is no object in myArray array that has an object
whose eating key contains the value chocolate. Thereby, the
<div> will not be displayed.
Also, you are missing a terminal condition in your loop:
for(let i = 0; i < myarray.length; i++) {
...
}
Next, you need to use the parameter passed in the method i.e food to evaluate in the if expression.
Alternatively, you could easily just do:
myArrayContainsEating(food) {
return this.myarray.find(e => e.eating === food);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With