Jerry's Blog

Recording what I learned everyday

View on GitHub


23 June 2019

Angular (10) -- Routing

by Jerry Zhang

Day 18: Angular Routing

Register routes in app.module.ts

const appRoutes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'users', component: UsersComponent },
  { path: 'servers', component: ServersComponent },
];

In the path, DO NOT add the slash /. Just write path: 'users'.

imports: [
    BrowserModule,
    FormsModule,
    RouterModule.forRoot(appRoutes)
  ],

Do not add the ref link in the tag. This will reload/refresh the page.

Use a directive routerLink instead:

<li role="presentation" class="nav-item active"><a class="nav-link" routerLink="/">Home</a></li>
<li role="presentation" class="nav-item"><a class="nav-link" routerLink="/servers">Servers</a></li>
<li role="presentation" class="nav-item"><a class="nav-link" [routerLink]="['/users']" >Users</a></li>

routerLinkActive attribute can be added at the <a> tag or <li> tag, depending on the bootstrap version.

This style will be activated when this link is activated.

The routerLink defines on which path this element is binding with. It will be triggered on any path CONTAIN this path.

To prevent the home path, which is /, always being triggered, we need to add routerLinkActiveOptions configuration.

<li role="presentation" class="nav-item">
  <a
    class="nav-link"
    routerLinkActive="active"
    routerLink="/"
    [routerLinkActiveOptions]="{exact: true}">Home</a>
</li>

Sometimes we want to do some logic before navigating. For example, we want to execute a function before navigating.

constructor(private router: Router) { }
onLoadServers() {
    //Some calculation
    this.router.navigate(['/servers']);
}

Config relative path in functions

By default, Angular does not know the current path. If we put a relative path in the navigate() method, Angular will always append this path after the root. However, we can change this by adding a relativeTo configuration.

We firstly need to inject the ActivatedRoute in the constructor.

constructor(private serversService: ServersService,
              private router: Router,
              private route: ActivatedRoute) { }
              
onReload() {
    this.router.navigate(['servers'], {relativeTo: this.route});
  }

In this way, Angular understands that our currently activated route and then we are free to use relative path now.

Dynamic Paths

Passing parameters in path

Adding a colon after the / in the path. Then id becomes dynamic.

{ path: 'users/:id', component: UserComponent },

Retrieve the data from URLs.

Getting data from the URL can give us the ability to get information from the URL input by users directly. Not only we can go to the URL by programming, but also can typed by users.

This currently loaded route is a Javascript object with a lot of metadata about this currently loaded route.

constructor(private route: ActivatedRoute) { }
{ path: 'users/:id/:name', component: UserComponent },
ngOnInit() {
    this.user = {
      id: this.route.snapshot.params['id'],
      name: this.route.snapshot.params['name']
    };
  }
<p>User with ID  loaded.</p>
<p>User name is </p>

Fetching route parameters reactive

Construct a path with an array:

<a [routerLink]="['/users', 10, 'Anna']">Load Anna (10)</a>

This will generate a path /users/10/Anna.

If we click this link navigating to the path above, the data on the screen is NOT updated! Why? Because we are already in this component. Angular will not reload the component even though we changed the url.

To let Angular know our subsequent changes, in our ngOnInit method, we should use the route to subscribe the changes.

ngOnInit() {
    this.user = {
      id: this.route.snapshot.params['id'],
      name: this.route.snapshot.params['name']
    };
    this.paramsSubscription = this.route.params
      .subscribe(
        (params: Params) => {
          this.user.id = params['id'];
          this.user.name = params['name'];
        }
      );
  }

this.route.params is an “observable”. This is async procedure. This function is executed whenever the params is changed. Then we update our parameters.

Angular cleans up the subscription for us whenever this component is destroyed. However, it’s better to destroy this subscription manually by implement an OnDestroy method.

ngOnDestroy(): void {
    this.paramsSubscription.unsubscribe();
  }

In this case, actually Angular will do this for us. But, when we create our own observable, we have to remember to destroy it by hand. Therefore, it is a good manner to do this now.

tags: Angular