Search code examples
angularngforangular-ng-if

Only first match from *ngIf directive returns ExpressionChangedAfterItHasBeenCheckedError


I have a nested ngif inside ngfor:

<ion-content>
    <ng-container *ngFor="let item of (results | async)">
      <ng-container *ngFor="let elements of item.bc; first as isFirst; index as i">
        <ng-container *ngIf="elements.Event.StartTime >= '2019-12-11T15:00:00' ?func():false">
          <ion-item>{{elements.Event.StartTime | date:'shortTime'}}</ion-item>
        </ng-container>
      </ng-container>
    </ng-container>
</ion-content>

I saw the resolution with a function from here: Show only first match from *ngIf expression

export class Tab4Page implements OnInit {

  results: Observable<any>;
  isFirstMatch = false;

  constructor(private channel: Service) {
  }

func() {
    if (this.isFirstMatch === false) {
      this.isFirstMatch = true;
      return true;
    } else {
      return false;
    }
  }

  ngOnInit() {

    this.results = this.channel.searchData();
  }

}

But it did not work for me. I get this error:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: true'. Current value: 'ngIf: false'.

Is there a better way to output only the first match? Or if not, can you please tell me how should I fix the ExpressionChanged error.


Solution

  • You can check for the first occurence inside your ts :

    html

    <ion-content>
        <ng-container *ngFor="let item of (results | async)">
          <ng-container *ngIf="findFirstElement(item.bc) as element">
              <ion-item>{{element.Event.StartTime | date:'shortTime'}}</ion-item>
            </ng-container>
        </ng-container>
    </ion-content>
    

    ts

      findFirstElement(item : any[]){
        if (!this.isFirstMatch && item.some(el => el.Event.StartTime >= '2019-12-11T15:00:00')){
          this.isFirstMatch = true ;
          return item.find(el => el.Event.StartTime >= '2019-12-11T15:00:00') ;
        }
    
        return null ;
      }
    

    update

    I think that isFirstMatch flag is no more needed because you want to render the first occurencce for each iteration (item) :

      findFirstElement(item : any[]){
          return item.find(el => el.Event.StartTime >= '2019-12-11T15:00:00') ;
      }