Efficient way to get route parameter in Angular

angular 7 get url parameters
angular redirect to route
angular route data
angular/router navigate with params
angular routerlink with params
would you like to add angular routing
router-outlet in angular
angular optional route parameter

How can I use router Observables more efficiently? If I need to load a single route parameter for example (let's say we have a route like /some-resource/:id), I need to subscribe to the router event, then to the route params to get the value. This requires two subscriptions and two unsubscribes.

I would like to:

  • Reduce boilerplate code
  • Make the code more readable
  • Get rid of subscriptions

Sample

export class SomeComponent implements OnInit, OnDestroy {
  private routerSub: Subscription;
  private routeSub: Subscription;

  someResource: Observable<SomeResourceType>;

  constructor(private someService: SomeService,
              private route: ActivatedRoute,
              private router: Router) {
    this.routerSub = this.router.events.subscribe((event) => {
      if (event instanceof NavigationEnd) {
        this.routeSub = this.route.params.subscribe((params) => {
          if (params['id']) {
            this.someResource = this.someService.findById(params['id']);
            // will access the resource using async pipe later
          }
        });
      }
    });
  }

  ngOnInit(): void {
  }

  ngOnDestroy(): void {
    this.routerSub.unsubscribe();
    this.routeSub.unsubscribe();
  }
}

The event subscription is needed to refresh the data if for some reason the component is not destroyed by angular, but still loaded using a different route param stackblitz example: https://stackblitz.com/edit/angular-router-basic-example-695kpb

You can use activated route for that.

constructor(route: ActivatedRoute) {
    this.id$ = route.params
        .pipe(pluck('id'));
}

You can use pluck. pluck('id') is basically the same as map(value => value.id). If you don't want to have a stream but the actual value, you can do the same and subscribe to it. But if you do that, don't forget to unsubscribe from the observable. You can do this with the take until operator.

id;
private _destroyed$ = new Subject<any>();

constructor(route: ActivatedRoute) {
    route.params
        .pipe(
            takeUntil(this._destroyed$),
            pluck('id')
        ).subscribe(id => this.id = id);
}

ngOnDestroy() {
    this._destroyed$.next();
    this._destroyed$.complete();
}

How To Get Route Path Parameters In Non-Routed Angular , Angular routing is a very useful and powerful feature which usually How To Get Route Path Parameters In Non-Routed Angular Components The Best Way To Unsubscribe RxJS Observable In The Angular Applications! Finally, our component needs to extract the route parameter from the URL. This is done via the ActivatedRoute service from angular/router module to get the parameter value. ActviatedRoute. The ActivatedRoute is a service, which keeps track of the currently activated route associated with the loaded Component.

Try this:

constructor(private route: ActivatedRoute) {}

ngOnInit() {
    const id = this.route.snapshot.params['id'];
}

The Angular 9/8 Router: Route Parameters with Snapshot and , How to Get Route Parameters. The Angular Router provides two different methods to get route parameters: Using the route snapshot,; Using  The Angular Router allows you to easily retrieve parameters from the URL which is an essential functionality that's required by most web applications. You can use both ways: the paramMap observable or the snapshot way but the latter requires you to be careful when re-using components. You can find the code in this repository.

As long as no one posts a better solution, here is mine:

I defined a RouterHelperService, which makes this process somewhat easier. One of the problem is, if you try to inject the ActivatedRoute instance directly in your service, you will be missing the params, so you need to pass it from your component to the service.

import { Injectable } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { filter, flatMap, map } from 'rxjs/operators';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class RouterHelperService {

  constructor(private router: Router) {
  }

  onNavigationEndReadParamByKey(route: ActivatedRoute, key: string): Observable<string> {
    return this.router.events.pipe(
      filter(event => event instanceof NavigationEnd),
      flatMap(() => {
        return route.params.pipe(
          filter(params => params[key]),
          map(params => params[key])
        );
      })
    );
  }
}

This way, in my component, I can call it with a single call and a single subscription.

export class SomeComponent implements OnInit, OnDestroy {
  private routeSub: Subscription;

  someResource: Observable<SomeResourceType>;

  constructor(private someService: SomeService,
              private route: ActivatedRoute) {
     this.routeSub = this.routerHelper.onNavigationEndReadParamByKey(this.route, 'id').subscribe((id) => {
        this.someResource = this.someService.findById(+id); //+id to convert it from a string to a number
     });
  }

  ngOnInit(): void {
  }

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

Route Parameters, allow you to pass information to your pages when you navigate to them. For instance, if you had a list of conversations, you could pass the conversation ID to a specific "single conversation" page when you click on one. Angular route definition with :id path param example. We can usually access this information in both sync and reactive ways in that particular component to which we navigated by injecting

Fastest way, which does not support component reload:

constructor(
  route: ActivatedRoute,
) {
  const myParam = route.snapshot.params.idThread;
}

Using the paramMap and the 'new' RxJs syntax, which support component reload:

constructor(
  route: ActivatedRoute,
) {
  route.paramMap.subscribe({
    next: params => {
      const myParam = params.get('myParam');
    }
  });
}

NB: unsubscribing is not mandatory in this case and should not lead to memory leaks

ParamMap, link A map that provides access to the required and optional parameters specific to a route. The map supports retrieving a single value with get() or multiple values with getAll() . Route Params. Creating routes with parameters is a common feature in web apps. Angular Router allows you to access parameters in different ways: Using the ActivatedRoute service, Using the ParamMap observable available starting with v4. You can create a route parameter using the colon syntax. This is an example route with an id parameter:

Using Route Parameters, The map supports retrieving single and multiple values from the query parameter. Methodslink. toString() link · mode_edit code  Define optional parameters in a separate object after you define the required route parameters. In general, prefer a required route parameter when the value is mandatory (for example, if necessary to distinguish one route path from another); prefer an optional parameter when the value is optional, complex, and/or multivariate.

In-app navigation: routing to views, The Angular router makes it a simple process to work with route parameters. The router provides a couple different ways to grab route parameters. We'll explore both Here we have a route with :username as the route parameter. Angular works hard to keep application performance as fast as possible. The Observable/Stream Way: Since Angular employs Observables heavily, the router also returns an Observable that we can listen to. We'll talk more on both of these options soon. Creating Routes with Parameters. Let's get the simple stuff out of the way. We'll create a route that has a route parameter.

ActivatedRoute, Those methods are get and getAll . Go for has method if you want to make sure if any particular parameter exists in the route with paramMap. Various ways of passing data to route. The Angular can pass data to Route in several ways. Using URL or Route Parameter; The Optional Parameter or Query Strings; Using URL Fragment; Static data using the data property; Dynamic data using state object; Passing static data to a route. The static data is configured at the time of configuring the route.

Comments
  • this is only way according to angular but rest is your logical way to this
  • Why do we need the _destroyed$? The subscribe method is called, so we still need to add a subscription, which we can unsubscribe from on destroy.
  • We need the _destroyed$ so that we don't need to unsubscribe. The takeUntil operator unsubscribes as soon as our component is destroyed. It might not make a big difference when you have only one subscriptions, but if you have many subscriptions in your component it is much cleaner to do it this way.
  • Have a read in the accepted answer here: stackoverflow.com/questions/38008334/… .
  • As I mentioned in my question, this won't handle the navigation event, so if the URL changes, your component won't be destroyed or re initiated, meaning copy-pasting URLs might not work.
  • If you change the url by overwriting it, the app will be reloading. You can reload the app, it works since it is read in ngOnInit.
  • You are right about the by manual change, but not if you are using routerLinks. Check this out: stackblitz.com/edit/angular-router-basic-example-695kpb (go to the catalog)
  • The problem mainly is, Angular won't destroy and recreate your component if you are routing to the same component. Meaning you have to specifically wait for such an event and change your state yourself. Feel free to enlighten me if I am missing something.