doorman
doorman

Reputation: 16959

Extract id from URL using Angular (2+ till latest)

Hi I am trying to extract the id part of the URL using Angular2.

http://localhost:3000/item/187809

I have been playing around with ActiveRoute within onInit but without luck

     this.route.queryParams.forEach((params: any) => {
       console.log("QUERYPARAMS");
       console.log(params);
     });

Also tried subscribing to route change like this

    this.routeSub = this.route.queryParams.subscribe(params => {
       console.log(params);
       console.log(+params['id']);
    }); 

but params is just an empty object.

I am defining the route as a lazy route like this

    {
        path: item',
        children: [
           { path: ':id', loadChildren: './item/item.module#ItemModule'},
        ]
    },

I think the problem is that I have a header component and a main component which holds the lazy loaded routed child. I am trying to load the id inside the header component.

Any idea what's missing?

Upvotes: 88

Views: 147821

Answers (8)

Falcon
Falcon

Reputation: 468

Based on @Sos Sargsyan answer, I'm presenting the same solution with an @Input decorator:

app.config.ts

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes, withComponentInputBinding())]
};

app.route.ts

export const routes: Routes = [
    {
        path: 'data/:sensorName',
        component: DataComponent,
        title: 'Data'
    }
]

data.component.ts

@Component({
    selector: 'app-data',
    standalone: true,
    imports: [RouterOutlet, RouterLink, CommonModule],
    templateUrl: './data.component.html',
    styleUrl: './data.component.scss'
  })
export class DataComponent implements OnInit, OnDestroy {
  @Input()
  set sensorName(name: string) {
    this.youService.getData(
      name
    ).subscribe();
  }
}

As the previous author mentioned, the component must also have an input property with the same name as the parameter passed by the router. In the example above, the property name is sensorName, which matches the parameter from the router path: sensorName.

withComponentInputBinding()

Enables binding information from the Router state directly to the inputs of the component in Route configurations. https://angular.dev/api/router/withComponentInputBinding?tab=api

@Input

The input property is bound to a DOM property in the template. During change detection, Angular automatically updates the data property with the DOM property's value.

https://v17.angular.io/api/core/Input

Upvotes: 0

Sos Sargsyan
Sos Sargsyan

Reputation: 365

Actually there are multiple ways of extracting id from router into the component. But I would like to mention that there is a new method in Angular. Starting with Angular 17 you can use withComponentInputBinding to bind route parameters directly to component's inputs. And in this case there is no need for manual subscription to route parameters. Here's how you can do it:

1.Enable the feature in app.config.ts file

const appRoutes: Routes = [];

bootstrapApplication(AppComponent,
  {
    providers: [
      provideRouter(appRoutes, withComponentInputBinding())
    ]
  }
);

2. Define your route in app.routes.ts file

import { Routes } from '@angular/router';

import { TasksComponent } from './tasks/tasks.component';
import { TaskDetailsComponent } from './tasks/task-details.component';

export const routes: Routes = [
  {
    path: 'tasks',
    component: TasksComponent,
  },
  {
    path: 'tasks/:taskId',
    component: TaskDetailsComponent,
  },
];

3. Extract taskId parameter in your TaskDetailsComponent

import { Component, input } from '@angular/core';

@Component({
  selector: 'app-task-details',
  standalone: true,
  templateUrl: './task-details.component.html',
  styleUrl: './task-details.component.css',
})
export class TaskDetailsComponent {
  taskId = input.required<string>();
}

Important Note:

If the route parameter is named taskId then the component must also have an input named taskId. If these names do not match, Angular will not be able to perform the binding, and the input will remain undefined.

Upvotes: 2

Chris Newman
Chris Newman

Reputation: 3312

Subscribing and Unsubscribing to Route Parameters

  1. Make sure you have configured a route that expects a parameter like so:
{path: 'item/:id', component: SomeItemComponent}
  1. Declare a variable for your route subscription. Import ActivatedRoute (not ActiveRoute) and inject it in your component constructor.
private routeSub: Subscription;
constructor(private route: ActivatedRoute) { }
  1. Inside ngOnInit in the same component, you can access the data in the params observable by subscribing to it like so:
ngOnInit() {
  this.routeSub = this.route.params.subscribe(params => {
    console.log(params) //log the entire params object
    console.log(params['id']) //log the value of id
  });
}
  1. Inside ngOnDestroy, unsubscribe to prevent memory leaks.
ngOnDestroy() {
  this.routeSub.unsubscribe();
}

Update - January 2021

There is a big difference between route.params and route.queryParams.

route.params, when subscribed to, returns an object with keys (that come from your route parameters, see step 1) and string values that are provided when navigating to the route. For example:

example.com/item/1

{
  itemId: '1'
}

route.queryParams, when subscribed to, returns an object with keys and string values that come from the query string (wiki) in the URL. For example:

example.com/welcome?var1=abc&var2=cde

{
  var1: 'abc',
  var2: 'cde'
}

route.queryParams will be undefined if a query string is not present in the URL. I believe OP, and some users in the comments have mistakenly used this instead of route.params.

Upvotes: 147

MattEnth
MattEnth

Reputation: 873

I suspect the issue is that you're using queryParams instead of just params.

params: An Observable that contains the required and optional parameters specific to the route.

queryParams: An Observable that contains the query parameters available to all routes.

so try this:

    this.route.params.subscribe(params => {
       console.log(params);
       console.log(+params['id']);
    });

Upvotes: 12

El houcine bougarfaoui
El houcine bougarfaoui

Reputation: 37403

    this.routeSub = this.route.params.subscribe(params => {
       console.log(params);
       console.log(+params['id']);
    });

Upvotes: 3

cgiacomi
cgiacomi

Reputation: 4699

I know I'm a bit late with a reply, but just in case you were still having problem please take a look at the Angular documentation.

angular routing tutorial

Look at the example from the link.

Start by importing ActivatedRoute:

    import { ActivatedRoute } from '@angular/router';

Then inject it in the constructor

    constructor(private route: ActivatedRoute) {}

And in OnInit()

    ngOnInit(): void {
        const id = this.route.snapshot.paramMap.get('id');
    }

and like this you don't need to worry about any Observables directly.

Hope this helps you.

Upvotes: 69

Mohammad Nazmul Hasan
Mohammad Nazmul Hasan

Reputation: 116

I have faced the same problem while working with Angular 8, and solved it by:

  1. At first, import ActivatedRoute:
    import { ActivatedRoute } from '@angular/router';
  1. Then, Inject ActivatedRoute in the constructor:
    constructor(private activatedRoute: ActivatedRoute) {}
  1. Your ngOnit method will look like this.
    ngOnInit(){
        const id = this.activatedRoute.snapshot.paramMap.get('id');
    }

I found it from the official documentation of Angular.

Upvotes: 4

Abolfazl Roshanzamir
Abolfazl Roshanzamir

Reputation: 14872

You have multi options to get id

    constructor(private route: ActivatedRoute) { }

1-With the help of params

    const id= this.route.snapshot.params['id'];

or

    const id = this.route.snapshot.params.id // any param name after "params"

2-With the help of paramMap

    const id= this.route.snapshot.paramMap.get('id')

3-subscribe to params (do not forget to unsubscribe)

      private subscription: Subscription

      constructor(private route: ActivatedRoute) { }
      ngOnInit(): void {
        this.subscription = this.route.params.subscribe(params => {
          const id = params['id']
        })
      }

     //To prevent memory leak
      ngOnDestroy(): void {
        if (this.subscription)
          this.subscription.unsubscribe()
      }

UPDATED

Imagine, you have the following route:
    {
      path: "",
      component: LayoutComponent,
      children: [
        {
          path: "action/:id", component: ChildComponent
        }
      ]
    }

If you are in the LayoutComponent and you want to get params of ChildComponent you have to use the following way:

    this.route.children.forEach(child => {
      child.params.subscribe(params => {
          const id = params['id']
      })
    }

Upvotes: 13

Related Questions