I am developing an angular app using the 8th version. Inside the ngIf
expression, I want to check something existanse inside array. So I have written the expression below:
*ngIf="questionniare.factors.some(item => item.intensities.length > 0)"
But now I get this error inside the console window:
Parser Error: Bindings cannot contain assignments at column 34 in [questionniare.factors.some(item => item.intensities.length > 0)]
But as see, I don't have any assignment in my condition. So what's the problem and how can I fix it?
(I know that I can define a method and do this job inside that method, but I want to know if this is a limitation on ngIf that I should consider next times?)
The error message mentions an "assignment" but the problem is that you are creating an arrow function inside of the component template, which is not allowed. A feature request has been posted on GitHub, asking to support the creation of these functions in Angular templates.
In order to use Array.prototype.some
in the template, you would have to define the predicate in the component code:
// You can define the predicate as a method
public itemHasIntensities(item): boolean {
return item => item.intensities.length > 0;
}
// You can also define the predicate as an arrow function
public itemHasIntensities = (item): boolean => item.intensities.length > 0;
and pass that function as an argument to Array.prototype.some
in the template:
*ngIf="questionniare.factors.some(itemHasIntensities)"
This stackblitz is similar to your original code and gives the same error. This other stackblitz shows the same example with the callback function defined in the component code.
That being said, and as mentioned in the question, the simplest solution is to evaluate the whole condition in a component method:
public showElement(): boolean {
return this.questionniare.factors.some(item => item.intensities.length > 0);
}
*ngIf="showElement()"
Note: memoizing the function would be recommended to avoid performance issues.
The problem is that your binding is iterating over the list and tracking a value that is being assigned in the background.
There are a couple solutions to this, first is putting your logic inside a public method on the component class that does this, which is the slower of the two solutions because every time change detection runs it will check your array value.
A better solution is to update a value on the component whenever the array changes
You can do that like this:
@Component({
selector: 'my-component',
templateUrl: 'my-component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
@Input()
set questionaire(value: Questionaire) {
this.questionaire$.next(value);
}
readonly questionaire$ = new ReplaySubject<Questionaire>(1);
readonly hasIntensities$ = this.questionaire$.pipe(
map(questionaire => questionniare.factors.some(item => item.intensities.length > 0))
);
};
Then in the template you can do something like this:
*ngIf="hasIntensities$ | async"
You could also accomplish it via change detector ref and ngOnChanges, but this should be the most efficient method
This is not written in Angular Documentation but looks like you can't use Array.some
in structural directives and you should move this logic into specific function inside the compnent.
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