简体   繁体   中英

Shared service: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked

I am not very experienced in Angular 4 so I am not sure how this problem works. I get the following error;

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

Here is my setup. I have a component "menus.component.ts" (MenusComponent) which loads other components using <router-outlet></router-outlet> The error happens at LocalService.placementListShow.value in the code below.

<div class="row">
  ...
</div>
<!-- end row -->
<div class="row">
  <div class="col-md-4 col-sm-4 col-xs-12 col-xl-3" *ngIf="LocalService.placementListShow.value">
    <div class="card m-b-20" *ngIf="LocalService.AllPlacements.Loaded && !LocalService.AllPlacements.Loading">
      ...
        <button type="button" class="list-group-item" [ngClass]="{'active': LocalService.AllPlacements.Active.value==placement.id }" (click)="LocalService.AllPlacements.Activate(placement.id)" *ngFor="let placement of LocalService.AllPlacements.Placements">{{placement.title}}</button>
      ...
    </div>
    <single-element-loader *ngIf="LocalService.AllPlacements.Loading"></single-element-loader>
  </div><!-- end col-->
  <div class="col-md-4 col-sm-4 col-xs-12 col-xl-3" *ngIf="LocalService.menuListShow.value">
    ...
        <a [routerLink]="[menu.id]" class="list-group-item" [ngClass]="{'active': LocalService.PlacementMenus.Active.value==menu.id }" (click)="LocalService.PlacementMenus.Activate(menu.id)" *ngFor="let menu of LocalService.PlacementMenus.Menus">{{menu.title}}</a>
    ...
    <single-element-loader *ngIf="LocalService.PlacementMenus.Loading"></single-element-loader>
  </div><!-- end col-->
  <div class="col-md-8 col-sm-8 col-xs-12 col-xl-9">
  <router-outlet></router-outlet>
  </div><!-- end col-->
</div>

The idea is that the component will load child components using Angular router. I want to control the visibility of certain widgets of the main component in the child components so I have setup a local service.

@Injectable()
export class LocalService {
  menuListShow = new BehaviorSubject(false);
  placementListShow = new BehaviorSubject(true);
  Menu: Menu = new Menu();
  AllPlacements: AllPlacements = new AllPlacements();
  PlacementMenus: PlacementMenus = new PlacementMenus();

  constructor(
      private MenuService: MenuService,
      private route: ActivatedRoute,
  ) {
  }

  changeMenuComponents(componentName: string): void {
    alert ("Changing to: "+ componentName)
    let menuState = {
      'placementList': (that): void => {
        that.menuListShow.next(false);
        that.placementListShow.next(true);
      },
      'menuList': (that): void => {
        that.placementListShow.next(false);
        that.menuListShow.next(true);
      }
    };
    menuState[componentName](this);
  }
}

For example. I have a MenuComponent and EditLinkComponent which will be loaded in the MenusComponent. There are 2 widgets which I would like to show depending on what component is loaded in the main component. But using the service I get the error above.

The following is not so important but to give you more idea about what I am trying to do.

I would like to show a menu placement listing when the user is seeing the index of the MenusComponent and when I click on the menu placement it should show menus in that placement and when I click on the menu it should show links in the menu. When I click on edit link it should show the EditLinkComponent. This happens through Angular router for example; #cms/menus then #cms/menus/{menuid} then #cms/menus/{menuid}/links/{linkid}/edit

The problem is if I refresh at; #cms/menus/{menuid}/links/{linkid}/edit I have get the error;

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

And I think this has to do with attempting to load the placement object and menu object from the server.

Here's how to fix it (you need to manually trigger a change detection):

@Injectable()
export class LocalService {
  menuListShow = new BehaviorSubject(false);
  placementListShow = new BehaviorSubject(true);
  Menu: Menu = new Menu();
  AllPlacements: AllPlacements = new AllPlacements();
  PlacementMenus: PlacementMenus = new PlacementMenus();

  constructor(
      private changeDetectorRef: ChangeDetectorRef,
      private MenuService: MenuService,
      private route: ActivatedRoute,
  ) {
  }

  changeMenuComponents(componentName: string): void {
    alert ("Changing to: "+ componentName)
    let menuState = {
      'placementList': (that): void => {
        that.menuListShow.next(false);
        that.placementListShow.next(true);
      },
      'menuList': (that): void => {
        that.placementListShow.next(false);
        that.menuListShow.next(true);
      }
    };
    menuState[componentName](this);
    this.changeDetectorRef.detectChanges();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM