Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

strange behaviour after added a resolver #32453

Closed
jyl1999 opened this issue Sep 3, 2019 · 3 comments
Closed

strange behaviour after added a resolver #32453

jyl1999 opened this issue Sep 3, 2019 · 3 comments
Labels
area: router freq2: medium P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent router: guards/resolvers router: navigation pipe events/scheduleNavigation/transitions observable state: confirmed type: bug/fix
Milestone

Comments

@jyl1999
Copy link

jyl1999 commented Sep 3, 2019

Affected package

@angular/router

Is this a regression?

No

Short description

After adding a resolver in my angular app with dynamic templating, there are strange behavior : the component is not displayed and behavior of ngswitch is broken in specific cases.

Expected behaviour

After resolver is finished, the DOM must always display layout2 with home component.

Minimal Reproduction

https://stackblitz.com/edit/angular-raidlg

Exception or Error

no error messages

Environment

Chrome 76.0.3809.132 (64 bits), Safari 12.1.2 (14607.3.9)

Angular Version

8.0.0 and same result with latest version 8.3.2

Test case

Test case in success :

  • A test case without simple resolver with dynamic templating is ok.
  • A test case with simple resolver without dynamic templating is ok.
  • A strange test case with resolver which return a simple Observable with no delays is ok (interesting to understand problem i think).
  • Test case with ngswitch (app.component.html )in this order is ok :
    <ng-container [ngSwitch]="layout">
    <app-layout1 *ngSwitchCase=1>
    <app-layout2 *ngSwitchCase=2>

Test case in error :

  • resolver with ngswitch (app.component.html) in this order :
    <ng-container [ngSwitch]="layout">
    <app-layout2 *ngSwitchCase=2>
    <app-layout1 *ngSwitchCase=1>
is ko ( same result with string in switchcase, same result with two *ngIf and ng container removed).

Informations to know about test case

Modules & Components Hierarchy :

AppModule->AppComponent
  LayoutModule->Layout1Component
              ->Layout2Component
  LoginModule->LoginComponent
  HomeModule->HomeComponent

app.component.html : (2 before 1 is important)

<ng-container [ngSwitch]="layout">
  <app-layout2 *ngSwitchCase=2></app-layout2>  
  <app-layout1 *ngSwitchCase=1></app-layout1>  
</ng-container>

app.component.ts

import { Component, OnInit } from '@angular/core';
import { Router, RoutesRecognized } from '@angular/router';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  layout: number = 1;

  constructor(private router: Router) { }

  ngOnInit() {

    this.router.events.subscribe((data) => {
      if (data instanceof RoutesRecognized) {
        this.layout = data.state.root.firstChild.data.layout;
      }
    });
  }
}

login.component.html

<div>
    <div>Login component</div>
    <div><a routerLink="/home">Home</a></div>
</div>

HomeResolver.ts

import { Resolve } from '@angular/router';
import { Observable, of } from 'rxjs';
import { Injectable } from '@angular/core';
import { delay } from 'rxjs/operators';

@Injectable(
    {
        providedIn : 'root'
    }
)
export class HomeResolver implements Resolve<Observable<String>> {
    resolve() {
        return  of("Test").pipe(delay(4000));
    }
}

home-routing.module.ts

const routes: Routes = [{path : 'home', data : { layout : 2}, component : HomeComponent, resolve : {resultat : HomeResolver}}];

DOM and log results

DOM result after /login

<my-app _nghost-fig-c0="" ng-version="8.0.0">
  <!--bindings={
    "ng-reflect-ng-switch": "1"
  }-->
  <!--bindings={
    "ng-reflect-ng-switch-case": "2"
  }-->
  <!--bindings={
    "ng-reflect-ng-switch-case": "1"
  }-->
  <app-layout1 _ngcontent-fig-c0="" _nghost-fig-c2="">
    <p _ngcontent-fig-c2="">Layout1 component</p>
    <router-outlet _ngcontent-fig-c2=""></router-outlet>
    <app-login _nghost-fig-c3="">
      <div _ngcontent-fig-c3="">
        <div _ngcontent-fig-c3="">Login component</div>
        <div _ngcontent-fig-c3=""><a _ngcontent-fig-c3="" routerlink="/home" ng-reflect-router-link="/home"
            href="/home">Home</a></div>
      </div>
    </app-login>
  </app-layout1>
</my-app>

DOM after home link clicked from login component (bug => layout2 added but login component not replaced by home component after end execution of resolver).

<my-app _nghost-aeg-c0="" ng-version="8.0.0">
  <!--bindings={
    "ng-reflect-ng-switch": "2"
  }-->
  <!--bindings={
    "ng-reflect-ng-switch-case": "2"
  }-->
  <app-layout2 _ngcontent-aeg-c0="" _nghost-aeg-c1="">
    <p _ngcontent-aeg-c1="">Layout2 component</p>
    <router-outlet _ngcontent-aeg-c1=""></router-outlet>
    <app-login _nghost-aeg-c3="">
      <div _ngcontent-aeg-c3="">
        <div _ngcontent-aeg-c3="">Login component</div>
        <div _ngcontent-aeg-c3=""><a _ngcontent-aeg-c3="" routerlink="/home" ng-reflect-router-link="/home"
            href="/home">Home</a></div>
      </div>
    </app-login>
  </app-layout2>
  <!--bindings={
    "ng-reflect-ng-switch-case": "1"
  }-->
</my-app>

Logs from console
12:05:15.603 app.component.ts:18 AppComponent -> constructor
12:05:15.619 app.component.ts:23 AppComponent -> ngOnInit
12:05:15.621 layout1.component.ts:15 Layout1Component -> constructor
12:05:15.623 layout1.component.ts:19 Layout1Component -> ngOnInit
12:05:15.628 console.ts:15 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
12:05:15.633 app.component.ts:26 Router event -> set layout : 1
12:05:15.639 login.component.ts:15 LoginComponent -> constructor
12:05:15.643 login.component.ts:19 LoginComponent -> ngOnInit
12:05:16.837 login.component.ts:22 LoginComponent -> onClick
12:05:16.838 app.component.ts:26 Router event -> set layout : 2
12:05:16.840 home.resolver.ts:17 HomeResolver -> resolve
12:05:16.844 layout2.component.ts:15 Layout2Component -> constructor
12:05:16.846 layout2.component.ts:19 Layout2Component -> ngOnInit
12:05:16.847 login.component.ts:15 LoginComponent -> constructor
12:05:16.847 login.component.ts:19 LoginComponent -> ngOnInit

@herzinger
Copy link

Any information on this? @jyl1999 have you been able to solve it?

I'm experiencing the same, and it broke my application's navigation seemly out of nowhere.

@herzinger
Copy link

An update: I don't know if it helps, but I was able to restore the correct behavior by removing this from the template:

  <ng-container *ngSwitchDefault>
    <router-outlet></router-outlet>
  </ng-container>

@jelbourn jelbourn added P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent and removed severity3: broken labels Oct 1, 2020
atscott added a commit to atscott/angular that referenced this issue Jun 28, 2022
…ones are destroyed

There can be timing issues with removing an old outlet and creating a
new one to replace it. Before calling `onChildOutletDestroyed`, the
`RouterOutlet` will first check to ensure that it is still the one
registered for that outlet name.

Fixes angular#36711
Fixes angular#32453
atscott added a commit to atscott/angular that referenced this issue Jun 28, 2022
…ones are destroyed

There can be timing issues with removing an old outlet and creating a
new one to replace it. Before calling `onChildOutletDestroyed`, the
`RouterOutlet` will first check to ensure that it is still the one
registered for that outlet name.

Fixes angular#36711
Fixes angular#32453
@atscott atscott modified the milestones: Backlog, Fixit H1'2022 Jun 28, 2022
atscott added a commit to atscott/angular that referenced this issue Jun 28, 2022
…ones are destroyed

There can be timing issues with removing an old outlet and creating a
new one to replace it. Before calling `onChildOutletDestroyed`, the
`RouterOutlet` will first check to ensure that it is still the one
registered for that outlet name.

Fixes angular#36711
Fixes angular#32453
dylhunn pushed a commit that referenced this issue Jun 28, 2022
…ones are destroyed (#46554)

There can be timing issues with removing an old outlet and creating a
new one to replace it. Before calling `onChildOutletDestroyed`, the
`RouterOutlet` will first check to ensure that it is still the one
registered for that outlet name.

Fixes #36711
Fixes #32453

PR Close #46554
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jul 29, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: router freq2: medium P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent router: guards/resolvers router: navigation pipe events/scheduleNavigation/transitions observable state: confirmed type: bug/fix
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants