1

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?

Jean D.
  • 169
  • 3
  • 15

2 Answers2

0

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.

Yuriy Kravets
  • 1,183
  • 2
  • 13
  • 28
  • Didn't solve my problem, but thanks for the hint to separate the routing out of the app routing into a specific routing for the child component! – Jean D. Apr 01 '20 at 13:03
0

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!

Jean D.
  • 169
  • 3
  • 15