Search code examples
angulartypescript

Is it possible to use linq in ngIf in Angular?


I'd like to use linq in ngIf but I'm getting an error.

Typescript:

public selectedStrategies: IStrategy[] = [];

html:

<div *ngIf="selectedStrategies.find(s => s.id === 3)">
  ...
</div>

Error:

Parser Error: Bindings cannot contain assignments at column 28 in [selectedStrategies.find(s => s.id === 3)]

Is this not allowed or am I doing something wrong?


Solution

  • We/I might need more information about what you are trying to do, but you could skip the find call and just set a property call current or whatever you are wanting to call it, and then just update that property as needed.

    To answer your main question, no, it isn't possible to call chainable array methods within an ngIf or @if.

    There are a few ways to do this though.

    One way would be to use angular's new signal system with the computed signal that would update everytime one of the signals changes:

    @Component({
      selector: 'app-example',
      standalone: true,
      imports: [CommonModule, FormsModule],
      template: `
        <div *ngIf="current() as itm">Item: {{ itm.name }}</div>
        <p>
          <input type="number" [(ngModel)]="id" />
        </p>
      `,
    })
    export class TestComponent {
      id = signal(3);
    
      items = signal([
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' },
      ]);
    
      // Whenever any of the signals updates this will also update.
      // Don't update signals here or you could end up in an endless loop.
      current = computed(() => this.items().find(item => item.id === this.id()));
    }
    

    Another way would be to use a pipe and you could pipe the data through, this is good for not having to re-render hundreds of times as a function often will do.

    @Pipe({ name: 'find', standalone: true })
    export class FindPipe implements PipeTransform {
      transform = (value: IStrategy[], id: number) => value.find(item => item.id === id);
    }
    
    @Component({
      selector: 'app-example',
      standalone: true,
      imports: [CommonModule, FindPipe],
      template: `
        <div *ngIf="items | find: 3 as itm">
          {{ itm.name }}
        </div>
      `,
    })
    export class TestComponent {
      items = [
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' },
      ];
    }
    

    Another way is to have a single property and set the current state on that property:

    @Component({
      selector: 'app-example',
      standalone: true,
      template: `<div>{{ current.name }}</div> `,
    })
    export class TestComponent {
      items = [
        { id: 1, name: 'Item 1' },
        { id: 2, name: 'Item 2' },
        { id: 3, name: 'Item 3' },
      ];
    
      current = this.items[0];
    
      setCurrent(id: number) {
        this.current = this.find(item => item.id === id);
      }
    }