Search code examples
angularlazy-loadingangular-routingangular-routerangular-routerlink

Angular: How to re-render a child component based on route change of parent app component?


My app renders a project component which contains information of a given ID from the URL like my.app/project/foo.

The app component:

  • uses the <router-outlet>to render the project component
  • contains a list of all projects in order to navigate to each project

The problem is: When you click a link, the route correctly changes with the project id, but the project component does not re-render again based on the new id. After reloading the project component renders correctly, but not after clicking on another id.

app.routing.module.ts:

const routes: Routes = [
...
  {
    path: 'project/:key',
    loadChildren: () =>
      import('../project-page/project-page.module').then(
        m => m.ProjectPageModule
      )
  }
...
];

app.component.html:

<a routerLink="/project/{{ project.id }}" *ngFor="let project of projects">
  {{ project.name }}
</a>
...
<div class="content">
  <router-outlet></router-outlet>
</div>

project-page.component.ts (within ProjectPageModule):

export class ProjectPageComponent implements OnInit {

  project: any;

  ngOnInit(): void {
    const id = this.route.snapshot.paramMap.get('id');

    return this.projectService
      .getProjectById(id)
      .pipe(delay(1000) /* debug only */)
      .subscribe(response => this.project = response);
    );
  }
  ...
}

project-page.component.html:

<h1>{{ project.id }}</h1>

I'm not sure if

  • the app component should "trigger" a new render of the project component, or maybe pass the id param from the url as an "input" to the project component ... or ...
  • the project component should listen to route changes, in a different way than my current implementation with the route snapshot.

What do you think?


Solution

  • The solution I came up with was that the child component needs to listen to route changes in its ngOnInit method:

      ngOnInit(): void {
        this.route.params.subscribe((param) => {
          this.getProjectFromUrl(param.id);
        });
      }
    
      getProjectFromUrl(id: number): any {
        return this.projectService
          .getProjectById(id)
          .pipe(delay(1000) /* debug only */)
          .subscribe(response => this.project = response);
        );
      }
    

    Yay!