14

I am trying to find out what is the best way to get the current route params in Angular 6.

At the moment I have to pass the ActivatedRoute to the service's method as argument and then use it in the service.

export class MainComponent {
    constructor(private dataService: DataService, private activeRoute: ActivatedRoute) { }

    getChartsData() {
        return this.dataService(this.activeRoute);
    }
}

@Injectable({
  providedIn: "root"
})
export class DataService {
    getChartsData(activatedRoute) {
        if (activatedRoute.snapshot.params['id']) {
            ...
        } else {
            ...
        }
    }
}
devDan
  • 5,969
  • 3
  • 21
  • 40
SMH
  • 889
  • 3
  • 11
  • 30
  • 2
    Can't you just inject `ActivatedRoute` in the service? – Roberto Zvjerković Sep 06 '18 at 13:36
  • this kind of depends on the structure of your router tree actually. This service being injected at root means it will only ever see the root level router params and not child params. – bryan60 Sep 06 '18 at 13:39
  • 1
    @ritaj I was doing that but I was getting empty object when I try to get the current route params. – SMH Sep 06 '18 at 13:47
  • 1
    using `snapshot.params` is only good for when the component first loads. what you're after is subscribing to the observable. `this.activatedRoute.params`. so it will be something like: `this.activatedRoute.params.subscribe((params: Params) => console.log(params['id']))` – Stavm Sep 06 '18 at 14:17

2 Answers2

11

Since you want the current route params, instead of activatedRoute.snapshot, you should be subscribing to activatedRoute.params. It will give you the latest and updated value of the current route params.

Your service method should not be responsible for getting the id from the ActivatedRoute. It should be the responsibility of your Component. Your service should only be responsible for getting the id from the component and then do the needful based on that id.

You should be extracting the id from the activatedRoute in your component. And then call the service method by passing it the id

export class MainComponent {

    subscription;

    constructor(
        private dataService: DataService, 
        private activeRoute: ActivatedRoute
    ) { }

    getChartsData() {
        this.subscription = this.activeRoute.params.subscribe(params => {
            if(params['id']) {
                this.dataService.getChartsData(params['id'])
                    .subscribe(data => console.log(data));
            }
        })
        
    }

    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
}

And in your service

@Injectable({
  providedIn: "root"
})
export class DataService {
    getChartsData(id) {
        if (id) {
            ...
        } else {
            ...
        }
    }
}
SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
3

In most cases services should not access routing. A "ChartDataService" should load and return charts that are identified by something (e.g. an id). Remember: If you access the current route directly in the service, you must never change the parameter name because this would break your data service.

export class ChartDataService {
  getChart(id: string) { … }
}

// in your component
const chartId = // read from activated route
this.chartsService.getChart(chartId);

If you really want to to access the current route in a service, you cannot inject ActivatedRoute (this is by design see e.g. https://github.com/angular/angular/issues/12884). But you can inject the Router itself and listen for navigation events:

class MyClass {
  constructor(private router: Router) {
    router.events.subscribe((val) => {
        // see also 
        console.log(val instanceof NavigationEnd) 
    });
  }
}

Example from https://stackoverflow.com/a/33548895/2085502.

Docs: https://angular.io/guide/router#router-events

Christoph Lütjen
  • 5,403
  • 2
  • 24
  • 33