Using array.prototype.some inside ngIf
Asked Answered
N

3

10

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?)

Nebiim answered 18/10, 2019 at 18:55 Comment(2)
You can always use pipes for such tasks .Look at this-#43118417Soluble
The assignment is certainly made in a hidden for loop to iterate over the array inside de Array.prototye.some functionHanford
H
17

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.

Himself answered 18/10, 2019 at 23:0 Comment(1)
Thanks ConnorsFan. Your attention about arrow function use inside a template was very helpful. Both your and @ElliotMendiola's answer are good enough to be marked as accepted.Nebiim
R
6

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

Ruination answered 18/10, 2019 at 19:11 Comment(3)
I'm not sure this is what he ask - he can do a lot of stuff to solve the specific issue - the question is if there is a limitation on using array pure method inside ngIf directiveGaut
He asked So what's the problem and how can I fix it? He wasn't specific how he wanted the solution, and I don't see him asking why he cant use an array pure method inside an ngif anywhereRuination
Thanks @ElliotMendiola and @YochaiAkoka, You both are true. I have first asked So what's the problem and how can I fix it? and then if this is a limitation on ngIf that I should consider next times?. So all notes and solutions are welcome.Nebiim
G
1

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.

Gaut answered 18/10, 2019 at 19:11 Comment(1)
So I think I should every time try functions to know if they work or not. This feels awful.Nebiim

© 2022 - 2024 — McMap. All rights reserved.