简体   繁体   中英

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?

You should separate your routes, so that app.routing.module contains only:

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

Then create another routing module, for example project-page.routing.module and import it in your ProjectPageModule . The routes for your submodule can be defined like this:

const appRoutes: Routes = [
    {
        path: '',
        component: ProjectPageEntryComponent,
        children: [
            {
                path: ':id',
                component: ProjectPageComponent
            }
        ]
    }
];

@NgModule({
    imports: [RouterModule.forChild(appRoutes)],
    exports: [RouterModule]
})
export class ProjectPageRoutingModule {}

and finally code for ProjectPageEntryComponent will be something like this:

@Component({
    template: '<router-outlet></router-outlet>'
})
export class ProjectPageEntryComponent {}

That way you handle only high-level navigations in your main app.routing.module and more concrete navigations for any SpecificModule -related navigations in its separate file.

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!

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