Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change a specific, internal route parameter in Angular2

I am building a calendar that can display different kinds of data. The following example explains my URL structure I think:

  • todo/2017/01/01 a day view of todos
  • birthdays/2017/01/01 a day view of birthdays
  • todo/2017/01 a month view of todos
  • birthdays/2017/01 a month view of birthdays
  • todo/2017 a year view of todos
  • birthdays/2017 a year view of birthdays

Up until now I have be able to pass in a Date object and reroute via

this.router.navigate([#HARDCODED# 'todo' #OR# 'birthday', year, ?month, ?day])

The problem is that I want to be able to navigate from todo/2017/01/01 => birthdays/2017/01/01 OR todo/2017/01 => birthdays/2017/01.

So I can't pass in the date parameters because some may not exist depending on which view I am in.

So how can I only switch out a single, internal parameter and reroute?

Something like

this.router.navigate(['todo', {ignoreTheRest: true}])

Otherwise I have to write a complicated switch statement for every possible combination.

like image 888
Nate May Avatar asked Jan 01 '17 20:01

Nate May


1 Answers

You can achieve this via the built-in ActivatedRoute service, your "one-stop-shop for route information", as they say in the documentation.

First, you need to inject the service in your component's constructor. Assuming that you have a Todo component an a Birthday component, in either case the constructor would look like:

constructor(private currentRoute: ActivatedRoute, private router: Router) { }

Then, in your ngOnInit() function, you need to subscribe to your ActivatedRoute instance's url property, which is an Observable:

ngOnInit() {
    this.currentRoute.url
        .subscribe(routeParts => {
            this.periodArray = [];
            for (let i = 1; i < routeParts.length; i++) {
                this.periodArray.push(routeParts[i].path);
            }
        });
}

The reason why your component route is provided as an Observable is that during your component's life cycle it can receive several different routes. Like in your case "/todo/2017" or "todo/2017/01" etc. Your component will only be created once, the ngOnInit() will also be called only once, but through subscribing to the ActivatedRoute.url observable, you will always get notified about the current route.

The above code block fills an array with all but the first url part from the activated route, which gives you all the passed parameters except for the initial "/todo" or "/birthday" segment.

Now you can navigate to the other component by simply adding the required path at the beginning of this parameter array, like:

navigateBirthdays() {
    this.periodArray.unshift('/birthday');
    this.router.navigate(this.periodArray);
}

Here is the full code for the Todo component and it's template:

todo.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';

@Component({
  templateUrl: './todo.component.html',
})
export class TodoComponent implements OnInit {

  periodArray = [];
  constructor(private currentRoute: ActivatedRoute, private router: Router) { }

  ngOnInit() {
    this.currentRoute.url
      .subscribe(routeParts => {
        this.periodArray = [];
        for (let i = 1; i < routeParts.length; i++) {
          this.periodArray.push(routeParts[i].path);
        }
      });
  }

  navigateBirthdays() {
    this.periodArray.unshift('/birthday');
    this.router.navigate(this.periodArray);
  }
}

todo.component.html

<p>
  List of Todo items for  {{periodArray.join("-")}}
</p>
<button (click)="navigateBirthdays()">Show Birthday items</button>

The Birthday component would look virtually identical. The above allows you to go back and forth between "/todo/2017/1/3" and "/birthday/2017/1/3" and also between "/todo/2017" and "/birthday/2017" etc. - without setting up any specific routing rules.

A side note: for optional parameters it is usually better not to include them in the URL path, but to provide them as an optional route object - see this section of the documentation.

like image 174
András Szepesházi Avatar answered Sep 21 '22 04:09

András Szepesházi