title: ExpressionChangedAfterItHasBeenCheckedError on Angular 6 while using <mat-tab>
body: <p>I have the following Error with Angular 6</p>
  
  <h2>Component</h2>
  
  <pre><code>&lt;mat-tab-group [(selectedIndex)]="selectedTabIndex"&gt;
    &lt;mat-tab label="Add"&gt;
      &lt;ng-template matTabContent&gt;
        &lt;form [formGroup]="entityAddFormGroup"&gt;
          &lt;dynamic-material-form [group]="entityAddFormGroup" [model]="entityAddFormCtlModelArray"&gt;&lt;/dynamic-material-form&gt;
          &lt;button (click)="buttonAddEntityClicked(entityAddFormGroup.value)"&gt;Add&lt;/button&gt;
        &lt;/form&gt;
      &lt;/ng-template&gt;
    &lt;/mat-tab&gt;
    &lt;mat-tab *ngIf="entityEditFormGroup &amp;&amp; currentEntity" label="Edit #{{currentEntity.id}}"&gt;
      &lt;!-- TODO correct bug with --&gt;
      &lt;ng-template matTabContent&gt;
        &lt;form [formGroup]="entityEditFormGroup"&gt;
          &lt;!-- &lt;h2 i18n&gt;Edit #{{currentEntity.id}}&lt;/h2&gt; --&gt;
          &lt;dynamic-material-form [group]="entityEditFormGroup" [model]="entityEditFormCtlModelArray"&gt;&lt;/dynamic-material-form&gt;
          &lt;button (click)="buttonEditEntityClicked(entityEditFormGroup.value)"&gt;Save&lt;/button&gt;
        &lt;/form&gt;
      &lt;/ng-template&gt;
    &lt;/mat-tab&gt;
  &lt;/mat-tab-group&gt;
  </code></pre>
  
  <p>when I remove the second <code>mat-tab</code> the error disappears</p>
  
  <p>Into other similar components, I didn't put the 2 forms into a <code>mat-tab-group</code> and <code>mat-tab</code> and don't have this error. </p>
  
  <p>Spent a while discovering where is the difference.</p>
  
  <h2>Error into console</h2>
  
  <blockquote>
    <p>ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ng-valid: true'. Current value: 'ng-valid: false'.</p>
  </blockquote>
  
  <h2>Environment</h2>
  
  <pre><code>Angular CLI: 6.2.8
  Node: 11.9.0
  OS: linux x64
  Angular: 
  </code></pre>
  
  <h2>ts file (export class ElectricityRateListComponent extends SelectableEntitiesListComponent)</h2>
  
  <pre><code>public displayedColumnsArray = [
      'select',
      'id',
      'energyRate',
      'mainTransmissionRate',
      'publicServiceRate',
      'validityStartDate',
      'validityEndDate',
      'electricityType',
      'city',
  ]; // Gives the order of the columns
  public statusMessage: string = ''
  public selectedTabIndex: number = 0
  
  
  protected _elTypeAddSelect: DBEntitySelect&lt;Enumerate&gt; //ElectricityType: Enumerate
  protected _elTypeEditSelect: DBEntitySelect&lt;Enumerate&gt; //ElectricityType: Enumerate
  
  protected _cityAddSelect: DBEntitySelect&lt;Enumerate&gt; //City: Enumerate
  protected _cityEditSelect: DBEntitySelect&lt;Enumerate&gt; //City: Enumerate
  
  constructor(
      protected router: Router,
      public messageService: MessageService,
      protected logger: LoggerService,
      protected route: ActivatedRoute,
      protected entitiesService: ElectricityRateService,
      protected enumeratesService: EnumerateService,
      protected formBuilder: FormBuilder,
      public formService: DynamicFormService,
      iconRegistry: MatIconRegistry,
      sanitizer: DomSanitizer,
      // private location: Location
  ) {
      super(router, messageService, logger, route, entitiesService, formBuilder, formService, iconRegistry, sanitizer, new ElectricityRate());
  
      (...)
  }
  
  
  
  /**
  * Common to add and edit forms
  *
  * @param aStrangeObject
  */
  protected _getCommonFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] {
      let lEntity: ElectricityRate = new ElectricityRate().deserialize(
      aStrangeObject
      )
      console.debug(
      "-----getAddFormControlModel-&gt;",
      aStrangeObject,
      lEntity.validityStartDate.constructor.name,
      lEntity.validityEndDate.constructor.name
      )
      const result: DynamicFormControlModel[] = [
      new DynamicInputModel({
          id: "energyRate",
          label: "Energy Rate",
          value: lEntity.energyRate,
          inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER,
          min: ElectricityRate.MIN_ELECTRICITY_RATE,
          max: ElectricityRate.MAX_ELECTRICITY_RATE,
          placeholder: "Energy Rate"
      }),
      new DynamicInputModel({
          id: "mainTransmissionRate",
          label: "Transmission Rate",
          inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER,
          min: ElectricityRate.MIN_ELECTRICITY_RATE,
          max: ElectricityRate.MAX_ELECTRICITY_RATE,
          value: lEntity.mainTransmissionRate.toString(),
          placeholder: "Transmission Rate"
      }),
      new DynamicInputModel({
          id: "publicServiceRate",
          label: "Public Service Rate",
          inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_NUMBER,
          min: ElectricityRate.MIN_ELECTRICITY_RATE,
          max: ElectricityRate.MAX_ELECTRICITY_RATE,
          value: lEntity.publicServiceRate.toString(),
          placeholder: "Public Service Rate"
      }),
      new DynamicInputModel({
          id: "validityStartDate",
          label: "Validity start date",
          inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_DATE,
          maxLength: 10,
          value: MiscHelper.dateToDynamicInputDate(lEntity.validityStartDate),
          placeholder: "Validity start date"
      }),
      new DynamicInputModel({
          id: "validityEndDate",
          label: "Validity end date",
          inputType: DYNAMIC_FORM_CONTROL_INPUT_TYPE_DATE,
          value: MiscHelper.dateToDynamicInputDate(lEntity.validityEndDate),
          placeholder: "Validity end date"
      })
      ]
      return result
  
  }
  
  /**
  * called by SelectableEntitiesListComponent-&gt;onInit
  *
  * @param aStrangeObject
  */
  protected _getAddFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] {
      //console.debug('getAddFormControlModel-&gt;aStrangeObject:', aStrangeObject)
      let lEntity: Enumerate = new Enumerate().deserialize(aStrangeObject)
      console.debug('-----getAddFormControlModel-&gt;aStrangeObject, lEntity:', aStrangeObject, lEntity)
      //Add form fields
      const result: DynamicFormControlModel[] = this._getCommonFormControlModel(aStrangeObject)
      result.push(this._elTypeAddSelect.asDynamicInputModel())
      result.push(this._cityAddSelect.asDynamicInputModel())
      return result
  }
  
  
  
  /**
  * Built onRowClicked
  *
  * @param anId
  * @param aStrangeObject can be a row of dataTable
  */
  protected _getEditFormControlModel(aStrangeObject: Enumerate): DynamicFormControlModel[] {
      console.log('getEditFormControlModel:', aStrangeObject)
      let result = this._getCommonFormControlModel(aStrangeObject)
      result = result.concat(DBEntity.getIdFormControlModel('id', aStrangeObject))
      result.push(this._elTypeEditSelect.asDynamicInputModel())
      result.push(this._cityEditSelect.asDynamicInputModel())
      // console.log('getEditFormControlModel:', result)
  
      return result
  }
  </code></pre>
  
  <h2>export abstract class SelectableEntitiesListComponent extends EntityListComponent {</h2>
  
  <pre><code>public ngOnInit() {
      super.ngOnInit()
      this._setSelects()
  }
  
  /**
  * redefine
  */
  public onReloadClicked(anEvent) {
      super.onReloadClicked(anEvent)
      this._setSelects()
  }
  
  
  /**
  * redefine
  */
  public afterEntityUpdatedSucessful(){
      super.afterEntityUpdatedSucessful()
      this._setSelects()
  }
  
  /**
  *
  */
  protected abstract _setSelects()
  
  
  }
  </code></pre>
  
  <h2>export abstract class EntityListComponent extends ReloadableComponent implements AfterViewInit, OnInit {</h2>
  
  <pre><code>protected _currentEntity: D = null // Set to null and not undefined cause of list.component.html tests for it  reason explained https://stackoverflow.com/questions/5076944/what-is-the-difference-between-null-and-undefined-in-javascript
  protected abstract displayedColumnsArray: Array&lt;string&gt;; // Gives the order of the columns
  public entitiesListTitle = this.constructor.name
  
  // FORMS
  entityAddFormGroup: FormGroup;
  entityAddFormCtlModelArray: DynamicFormControlModel[];
  entityEditFormGroup: FormGroup;
  entityEditFormCtlModelArray: DynamicFormControlModel[];
  
  // DATA TABLE variables
  dataSource: SseEntityDataSource&lt;D&gt;;
  selectionModel = new SelectionModel&lt;D&gt;(true, []);
  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;
  
  constructor(
      protected router: Router,
      public messageService: MessageService,
      protected logger: LoggerService,
      protected route: ActivatedRoute,
      protected entitiesService: SseEntityService&lt;D&gt;,
      protected formBuilder: FormBuilder,
      public formService: DynamicFormService,
      iconRegistry: MatIconRegistry,
      sanitizer: DomSanitizer,
      public entityPrototype: DBEntity,
      // private location: Location
  ) {
      super(
      iconRegistry,
      sanitizer,
      )
      if (entityPrototype === undefined || entityPrototype == null){
      throw new Error('constructor error, create me in the caller entityPrototype!')
      }
  }
  
  /**
  * calls this._getAddFormControlModel() and adds it to entityAddFormCtlModelArray
  */
  public ngOnInit() {
      // console.debug('ngOnInit called')
      if (this.entityPrototype === undefined){
      throw new Error('entity-list.component-&gt;ngOnInit-&gt; this.entityPrototype is undefined, set it into constructor of descendant')
      }
      this.entitiesListTitle = StringHelper.camelCaseToSpaces(this.constructor.name.replace('Component', ''))
  
  
      this.dataSource = new SseEntityDataSource&lt;D&gt;(this.logger, this.entitiesService, this, this.entityPrototype);
      this.setMessageService();
      this.entityAddFormCtlModelArray = this._getAddFormControlModel(this.entityPrototype);
      this.entityAddFormGroup = this.formService.createFormGroup(this.entityAddFormCtlModelArray);
  
      this.dataSource.loadEntities()
  }
  
  protected abstract _getCommonFormControlModel(aStrangeObject: DBEntity): DynamicFormControlModel[]
  protected abstract _getAddFormControlModel(aStrangeObject: DBEntity): DynamicFormControlModel[]
  
  public ngAfterViewInit() {
      this.dataSource.paginator = this.paginator;
      this.dataSource.sort = this.sort;
  //    this.cdr.detectChanges();
  }
  
  get currentEntity(): D {
      return this._currentEntity;
  }
  
  set currentEntity(value: D) {
      this._currentEntity = value;
      this.entitiesService.currentEntity = value;
  }
  
  /**
  * Require dataSource not null
  */
  public loadDatasourceWithPaginator() {
      // Init currentEntityId
      try {
      this.dataSource.loadEntities();
      } catch (e) {
      this.messageService.add(new UserMessage('Error loading entities', e, UserMessageType.Error));
      throw e;
      }
  }
  
  public applyFilter(filterValue: string) {
      filterValue = filterValue.trim(); // Remove whitespace
      filterValue = filterValue.toLowerCase(); // Datasource defaults to lowercase matches
      this.dataSource.filter = filterValue;
  }
  
  
  /**
  * Require dataSource not null
  */
  public setMessageService() {
      this.dataSource.messagesForUsers$.subscribe(
      usrMessage =&gt; {
          this.messageService.add(usrMessage);
      }
      );
  }
  
  
  abstract onRowClicked(row: any): void;
  
  public buttonAddEntityClicked(dataValues: any) {
      console.debug('buttonAddEntityClicked--------&gt;from Entitylist.components dataValues:', dataValues);
      let lEntity = this.entityPrototype.deserialize(dataValues, false)
      console.debug('buttonAddEntityClicked--------&gt;from Entitylist.components lEntity:', lEntity);
      console.debug('buttonAddEntityClicked--------&gt;from Entitylist.components lEntity.toJSON():', lEntity.toJSON());
  
      this.entitiesService.addEntityFromFormData(lEntity.toJSON()).subscribe(
      lData =&gt; {
          const msg = `Entity added successfully`;
          this.messageService.add(new UserMessage(msg, lData, UserMessageType.Info));
          this.afterEntityUpdatedSucessful()
      },
      lError =&gt; {
          const msg = `Entity add Error`;
          console.error('buttonAddEntityClicked-&gt;Error:', lError)
          this.messageService.add(new UserMessage(msg, lError, UserMessageType.Error));
          throw lError;
      }
      );
  }
  
  public afterEntityUpdatedSucessful(){
      this.loadDatasourceWithPaginator();
  }
  
  
  public buttonEditEntityClicked(jsonStringValues: string) {
      this.logger.debug('buttonAddEntityClicked-&gt; from Entitylist.components:', jsonStringValues);
      let lEntity = this.entityPrototype.deserialize(jsonStringValues, false)
      this.logger.debug('buttonEditEntityClicked-&gt; Entitylist.components: jsonStringValues, lEntity:', jsonStringValues, lEntity);
  
      this.entitiesService.updateEntityFromFormData(lEntity.toJSON()).subscribe(
      lData =&gt; {
          const msg = `Entity updated successfully`;
          this.messageService.add(new UserMessage(msg, lData, UserMessageType.Info));
          this.afterEntityUpdatedSucessful()
      },
      lError =&gt; {
          const msg = `Entity update Error`;
          console.error('buttonEditEntityClicked-&gt;Error:', lError)
          this.messageService.add(new UserMessage(msg, lError, UserMessageType.Error));
          throw lError;
      }
      );
  }
  
  
  public buttonRemoveSelectedRowsClicked() {
      let toReloadObservable: Observable&lt;Object&gt; = null;
      this.selectionModel.selected.forEach(item =&gt; {
      this.logger.debug('Deleting selected item:', item);
      toReloadObservable = this.entitiesService.deleteFromId(item.id);
      toReloadObservable.subscribe(
          data =&gt; {
          const msg = `Entity ${item.id} deleted successfully`;
          this.messageService.add(new UserMessage(msg, data, UserMessageType.Info));
          this.afterEntityUpdatedSucessful()
          },
          error =&gt; {
          const msg = `Error while deleting entity ${item.id}`;
          this.messageService.add(new UserMessage(msg, error, UserMessageType.Error));
          throw error;
          }
      );
      });
      this.selectionModel = new SelectionModel&lt;D&gt;(true, []);
      this._currentEntity = null;
      // When all are removed reload data source
  }
  
  public onReloadClicked(anEvent) {
      this.loadDatasourceWithPaginator();
  }
  
  public buttonMasterToggleClicked() {
      this.isAllSelected() ?
      this.selectionModel.clear() :
      this.dataSource.data.forEach(row =&gt; this.selectionModel.select(row));
  }
  
  public sampleAddButtonClicked() {
      Constants.SAMPLE_COMPANIES_JSON_DATA.forEach( (entity) =&gt; {
      // console.log('sampleAddButtonClicked', JSON.stringify(entity));
      this.buttonAddEntityClicked(entity);
      });
  }
  
  public isAllSelected() {
      const numSelected = this.selectionModel.selected.length;
      const numRows = this.dataSource.entitiesCount();
      return numSelected === numRows;
  }
  
  protected _updateEditFormFields(toUpdate: any) {
      console.log("updateEditFormFields-&gt;toUpdate, model", toUpdate, this.entityEditFormCtlModelArray);
      Object.entries(toUpdate).forEach(([key, value]) =&gt; {
      // console.log('updateEditFormFields-&gt;setting key', key, 'value:', value);
      const inputModel = this.formService.findById(key, this.entityEditFormCtlModelArray) as DynamicInputModel;
  
      if (inputModel == null) {
          throw new Error('updateEditFormFields-&gt;InputModel is null, key ' + key + ' not found into entityEditFormCtlModel val:' + value );
      }
      inputModel.valueUpdates.next(value as string)//If not reloading recreate the formGroup with this.entityAddFormGroup = this.formService.createFormGroup(this.entityAddFormCtlModelArray);
      // inputModel.valueUpdates.subscribe(value =&gt; console.log('new value assigned to field: ', newVal));
      // inputModel.disabledUpdates.next(true);
      });
  }
  
  
  }
  </code></pre>
  
  <p>Highly related to <a href="https://stackoverflow.com/a/49667060/2118777">this post</a></p>