Muirik Muirik - 28 days ago 7
TypeScript Question

Handling Dynamic URL Params via RouterLink in Angular App

In my Angular 2 app I have a tab area where users can select from a group of independent, but contextually related components. When they click on one of these links, the relevant component loads according to what's defined in the routerLink, like this:

<a class="page-content-header-item" routerLink="/page1" routerLinkActive="selected">Page 1</a>


This was working well. However, since then we've built the app to save various user-selected filter selections as params in the URL. This way when they re-load the component, they'll have their most recent selections still visible and applied to the data. So the URL might look like this after the user had made some filter selections:

http://somesite.com/page1;language_filter=true;language_selection=English


The component code for this looks like this:

public changePage(page, value, type, body)
{
this.onUserSelection(value, type, body, page);

this.route.params.subscribe(
(params: any) => {
this.page = params['page'];
this.language_filter = params['language_filter'];
this.language_selection = params['language_selection'];
}
);
this.router.navigate(
['/page1', {
page: page,
language_filter: this.language_filter,
language_selection: this.language_selection,
}]);
}


This works well for the main navigation methods, that are accomplished via a routing file, where each one looks like this:

{ path: 'page1', component: Page1Component, canActivate: [AuthGuard], data: {contentId: 'page1'} }


However, for this tab area I mentioned, it's loading components according to a hard-coded routerLink param. So I realize now that when a user navigates BACK to a component that way, as opposed to via one of the other ways we make available, it actually overrides the URL params - because it's literally loading "page1" -- because of this
<a class="page-content-header-item" routerLink="/page1" routerLinkActive="selected">Page 1</a>


... and thus the URL params that had been added previously are wiped out.

So, my question is, is there a way I can edit this code:

<a class="page-content-header-item" routerLink="/page1" routerLinkActive="selected">Page 1</a>


... so it allows for some dynamic variables? Or do I have to find a new way to handle the navigation in this tab area?

Answer Source

Here is the solution I came to using queryParams.

First, you can pass parameters in your routerLink directive using the queryParams directive:

<a routerLink="/page1" [queryParams]="fooParams">Page 1</a>
<a routerLink="/page2">Page 2</a>
<router-outlet></router-outlet>

where fooParams is a plain object:

export class MainComponent {
  fooParams = {
    language_filter: true,
    language_selection: 'english'
  }
}

Angular will output this url like

href="localhost:4200/page1?language_filter=true&language_selection=english"

What you have to do next, is set up a way to intercept the ActivatedRoute, so you can extract the values of the params from the ActivatedRouteSnapshot. You can do this either using a resolver or directly in your component. In my example I used a resolver:

@Injectable()
export class RoutingResolve implements Resolve<any> {
  resolve(routeSnapshot: ActivatedRouteSnapshot) {
    const { language_filter, language_selection } = routeSnapshot.queryParams;
    return { language_filter, language_selection };
  }
}

And then pass that resolver in the route definition:

const ROUTES: Routes = [
  { 
    path: 'page1',
    component: PageOneComponent,
    // In this route we define a resolver so we can intercept the 
    // activatedRoute snapshot before the component is loaded
    resolve: {
      routing: RoutingResolve
    }
  },
  { 
    path: 'page2',
    component: PageTwoComponent
  }
];

Then, inside PageOneComponent you can subscribe to the resolved data and do whatever you want with it, like for example, setting the value of a form with it and updating the queryParams on form change.


For the full example, check out this plunker

Make sure to open the preview in a separate window, so you can see the route changes in your browser.

If you navigate to Page 1, change the values in the form, then navigate to Page 2, and then press back in your browser, you can see the values loaded in the form correspond to the params in the url.