*ngFor angular 2 when creating tabs - Expression has changed after it was checked

709 views Asked by At

I'm using the tab project explained here: Tabs Project

Everything else but my issue works perfectly. The only thing that doesn't work for me, at the moment, is applying *ngFor when creating tabs.

I know that the 2nd-phase checking by angular detects changes, and he's right, the tabs might be adding while the 2nd-phase check is in progress.

What I want to do is to try and still make it work, it's super important to me to use *ngFor within the tabs selector.

Provided is a Plunker code demonstrating the crash and what I'm trying to achieve.

Plunker Code

Important to say, Ive looked into

and I understand that its only on debug mode and what the answerer said, though it was a year ago.

In Addition

Unlike the Plunker which able run the code with errors in the console (that's the explanation of the issue), I cant even switch tabs in my project, but that's a normal behavior, I don't want bad code.

Unfortunately, I cant share my real code because its for my work basically, but I can provide more data if needed, though it is based almost 100% from the Plunker and the project I provided in the beginning of the issue. .

2

There are 2 answers

3
eko On BEST ANSWER

One solution is to wrap your "zone" code with setTimeout (other methods for triggering change detection manually will also work)

if(activeTabs.length === 0) {
      setTimeout(()=>{
        this.selectTab(this.tabs.first);
      },0);
}

Full plunker: https://plnkr.co/edit/UVfiJFYexgua2HfPe0Lw?p=preview

1
Fjut On

In order to fix the issue you need to remove the code for setting the first tab to active from your ngAfterContentInit() method. This code is causing the issue:

if(activeTabs.length === 0) {
  this.selectTab(this.tabs.first);
}

I assume that the error pops up because change detection requires that the DOM is stabilized after one run, and your call in the ngAfterContentInit() would require anothed pass of CD to reflect the new tab.active value in the DOM.

What you could do instead is set the first element in your *ngFor to be active by default. Something like:

<tab *ngFor="let item of ['1','2']"; let index = index" [active]="index == 0"...

EDIT: Seems you can also use the first local variable (haven't tried it). See this plunkr