7

I am building an app where the first url segment represents the language of the interface, like :

/en/customer/3
/en/shop

My router is set up like this:

{ path: ':lang/customers/:id', component: CustomerComponent },
{ path: ':lang/shop', component: ShopComponent },

I want to use the language param from the url (lang = 'en' in this example) in the bootstrapped AppComponent or in a translation service. I have access to this param in the ShopComponent and CustomerComponent, but nowhere else in the code. When I enter this in AppComponent:

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

ngOnInit() {
  this.router.routerState.root.params.subscribe((params: Params) => {
    console.log('params: ',params);
  }
  this.activatedRoute.params.subscribe((params: Params) => {
    console.log('params: ',params);
  }
}      

I get two empty objects. Also the url param remains empty.

What am I doing wrong? Maybe more importantly, I am obviously missing some conceptual understanding of routers, but I cannot find any helpful information in the docs or elsewhere.

Thanks for your help!

Carlo Roosen
  • 1,025
  • 9
  • 15
  • Dup: http://stackoverflow.com/questions/35688084/how-get-query-params-from-url-in-angular2/39146396#39146396 – Baruch Dec 19 '16 at 16:51
  • No not a dup. In fact the code I describe is exactly what you find as the accepted solution in the other article. However, this does not work in this case. – Carlo Roosen Dec 20 '16 at 09:34

3 Answers3

12

Trying to answer my own question, I think there is NO easy way to do it the way I thought. The router setup like

{ path: ':lang/customers/:id', component: CustomerComponent } 

attaches the entire path to the CustomerComponent, making lang and id both available parameters there. From this perspective it is clear why those parameters are not accessible outside CustomerComponent.

What I ended up doing is redefine my router like so:

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { LanguageComponent, CustomerComponent, ShopComponent } from "./";

@NgModule({
    imports: [
    RouterModule.forRoot([
      { path: ':lang', component: LanguageComponent ,
        children: [
          { path: 'shop', component: ShopComponent },
          { path: 'customer/:id', component: CustomerComponent },
          { path: '**', redirectTo: '/shop', pathMatch: 'full' }
        ]
      },
            { path: '**', redirectTo: '/en', pathMatch: 'full' }
    ])
  ],
  exports: [
    RouterModule
  ]
})
export class AppRoutingModule {}

Then I created a LanguageComponent as a Routing Component.

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

import { TranslateService } from './'
@Component({
  template : '<router-outlet></router-outlet>'
})
export class LanguageComponent implements OnInit {

  constructor( private activatedRoute : ActivatedRoute, private translateService: TranslateService) {
  }

  ngOnInit() {
    this.activatedRoute.params.subscribe( (params : Params) => {
      this.translateService.setLanguage( params['lang'] );
    });    
  }
}

Then I store the language in TranslateService, which is globally available.

Carlo Roosen
  • 1,025
  • 9
  • 15
  • 1
    Great solution. The only issue is that linking will have to be relative in all components and it can get really messy really quick. Have you thought of programmatically setting the base href instead? – Spock Sep 29 '17 at 11:56
  • Did you find any way to do it with updated version of Angular, which can manipulate URL according to language ? – Praveen Rana Jan 18 '18 at 07:07
  • I've tried many solution. This one probably one of the best. I just use Guard instead subscriber. `@Injectable() /n export class LangGuard { canActivate(translateService: TranslateService, lang: string): boolean { this.translateService.setLanguage( params['lang'] ); } } export const canActivateLang: CanActivateFn = (route: ActivatedRouteSnapshot) => { return inject(LangGuard).canActivate(inject(TranslateService), route.params[ApiHeaderKeys.lang]!) }` – SV0505 May 24 '23 at 17:18
2

Check out this post about getting route params

Getting the parameter from a route

this.subscription = this.activatedRoute.params.subscribe(
 (param: any) => {
   let language = param['lang'];
   this.chosenLang = language; // Access to the lang
 });

In your component where you want to get the route paramter

app.component.ts

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

@Component({
  selector: 'my-app',
  template: `<blah></blah>`,
  styles: []
})
export class AppComponent implements OnInit, OnDestroy {
  private subscription: Subscription;
  chosenLang: string = "";

  constructor(private activatedRoute: ActivatedRoute) { }

  ngOnInit() {
    // subscribe to router event
    this.subscription = this.activatedRoute.params.subscribe(
     (param: any) => {
       let language = param['lang'];
       this.chosenLang = language; // Access to the lang
     });
  }

  ngOnDestroy() {
    // prevent memory leak by unsubscribing
    this.subscription.unsubscribe();
  }

}
Community
  • 1
  • 1
Logan H
  • 3,383
  • 2
  • 33
  • 50
  • The problem is, how can I read the url? In other words, where do I call setLang() ? I dont want to set the language in ShopComponent or CustomerComponent, In that case I would need to do it in every compontent. So far it is the only place where I have access to the url, as it seems. – Carlo Roosen Dec 19 '16 at 16:13
  • Ok so before sharing the url, you need help reading the url. Give me moment – Logan H Dec 19 '16 at 16:17
  • may i know how will we write routes config/path for fetching language parameter? localhost/en – mevr Feb 18 '21 at 09:22
0

This might do what you want

constructor(router:Router) {
  router.events.filter(e => e instanceof NavigationEnd).subscribe(e => {
    console.log('lang', router.routerState.root.params['lang']);
  });
}

It should work in services and components.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • No luck. this.router.routerState.root.params actually is an Observable. When I subscribe to it (wich means I have 2 nested subscribe calls), it returns an empty object. – Carlo Roosen Dec 19 '16 at 17:44
  • @ günter your code suggests that my code did not work because the router was not ready. I think that is not the case, whatever I try the results are consistent: The root is basically a barebone router object with no values for params, url, queryParams, children. As if my url was just '/'. A snapshot gives the same result, even when I take it after 1 second. – Carlo Roosen Dec 20 '16 at 10:23