1

I have an Angular 10 application, I am trying to remove the navside component from the login component, so I created a service on the nave side component contains this code :

visible: boolean;

  constructor() {
    this.visible = true;

  }
  show() {
    this.visible = true;

  }
  hide() {
    this.visible = false;
  }
  toggle() {
    this.visible = !this.visible;
  }
  doSomethingElseUseful() { }

and inside the naveside component i put :

export class NavsideComponent implements OnInit {


  constructor(public sr: ServService ) { }

  ngOnInit(): void {
    
  }

and the Html component :

<div *ngIf="sr.visible">
    <mat-sidenav-container class="example-container">
        <mat-sidenav #sidenav mode="push" class="app-sidenav" opened>
            <mat-toolbar class="co">
                <span class="toolbar-filler"></span>

.
.
.
.
.
. </div>

but this error was displayed :

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

EDIT 1

Login.component.ts

import { Component, OnInit } from '@angular/core';
import { ServService } from '../../navside/serv.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  constructor( private sr :ServService) { }

  ngOnInit(): void {
    this.sr.hide();
    this.sr.doSomethingElseUseful();
  }

}

EDIT 2

Stackblitz putting together the snippets above, where the warning can be seen:

https://stackblitz.com/edit/angular-ivy-vbkytu?file=src/app/login/login.component.ts

francisco neto
  • 797
  • 1
  • 5
  • 13

1 Answers1

2

I have edited your post to include a Stackblitz with a minimal reproducible example of the reported error. I suggest that in your next posts you include a minimal reproducible example, hence it´s more likelly you will have an answer.

About ExpressionChangedAfterItHasBeenCheckedError warning

This post has usefull informations about this warning: Expression ___ has changed after it was checked

In your specific case, the warning ExpressionChangedAfterItHasBeenCheckedError is shown because the value of sr.visible is changed twice during the initialization process:

  • once during the service SerService creation and
  • again in loginComponent.ngOnInit() when you call sr.hide();

In the same round of change detection a value that is binded in the view (sr.visible is binded in <div *ngIf="sr.visible">) is not supposed to change values more than once, that's the reason of the warning.

Solving your problem calling cdr.changeDetection() in the right component

You can solve the problem calling cdr.detectChanges() in order to fire a second round of change detections. But for that to work, you need to call it in the component that has the affected binding.

Calling cdr.detectChanges() on LoginComponent has no effect, since the binding of <div *ngIf="sr.visible"> is not in that component. You should call cdr.detectChanges() in the parent component where the binding is.

That said, the following use of cdr.detectChanges() in LoginComponent will NOT solve the problem:

    export class LoginComponent {
      constructor(private sr: ServService, private cdr: ChangeDetectorRef) {}
    
      ngOnInit() {
        this.sr.hide();
        this.sr.doSomethingElseUseful();
    
        //code bellow will NOT SOLVE the problem:
        this.cdr.detectChanges();
      }
    }

What will solve the problem is invoking cdr.detectChanges() on the component that has the binding <div *ngIf="sr.visible">.

In my working stackblitz (at the end of this answer), that component is AppComponent:

app.component.html:

    <div *ngIf="sr.visible">
        Toolbar here
        <!-- your mat-side-nav and mat-toolbar here -->
    </div>
    <app-login></app-login>

So, the cdr.detectChanges() is called in the ngOnInit() of app.component.ts:

    export class AppComponent {
      constructor(public sr: ServService, 
        private cdr: ChangeDetectorRef) {}
    
      ngOnInit() {
        this.cdr.detectChanges();
      }
    }

Working version - stackblitz

The working version calling detectChanges in the right component is available in the following Stackblitz:

https://stackblitz.com/edit/angular-ivy-nbb7bz?file=src/app/app.component.ts

francisco neto
  • 797
  • 1
  • 5
  • 13