319

Is there anyway to send data as parameter with router.navigate? I mean, something like this example, as you can see the route has a data parameter, but doing this it's not working:

this.router.navigate(["heroes"], {some-data: "othrData"})

because some-data is not a valid parameter. How can I do that? I don't want to send the parameter with queryParams.

Jota.Toledo
  • 25,115
  • 9
  • 55
  • 68
Motomine
  • 3,659
  • 5
  • 18
  • 21

7 Answers7

784

There is a lot of confusion on this topic because there are so many different ways to do it.

Here are the appropriate types used in the following screen shots:

private route: ActivatedRoute
private router: Router

1) Required Routing Parameters:

enter image description here

2) Route Optional Parameters:

enter image description here

3) Route Query Parameters:

enter image description here

4) You can use a service to pass data from one component to another without using route parameters at all.

For an example see: https://blogs.msmvps.com/deborahk/build-a-simple-angular-service-to-share-data/

I have a plunker of this here: https://plnkr.co/edit/KT4JLmpcwGBM2xdZQeI9?p=preview

Nasta
  • 677
  • 7
  • 18
DeborahK
  • 52,690
  • 10
  • 99
  • 123
  • 4
    thank you for your answer! What is the difference between the 2) and the 3)? Because both end up adding "?parameter=" in the URL. Could you give me an example for the 4)? I can't figure out how to do it. – Motomine Jul 01 '17 at 22:38
  • I updated by answer to show the different URLs and to provide a link to a blog post and plunker on how to pass data with a service. The URL is different with optional and query parameters as shown above. Plus query parameters can be retained across routes. – DeborahK Jul 01 '17 at 22:50
  • 8
    I also have a Pluralsight course on routing that covers all of this: https://app.pluralsight.com/library/courses/angular-routing/table-of-contents You can sign up for a free week if you are interested in more information. – DeborahK Jul 01 '17 at 22:51
  • Thank you! I think I will do it with the service just because I don't want to show the parameters, but in some cases the other uses might work – Motomine Jul 02 '17 at 20:45
  • @DeborahK, I think there is a small mistake in the photo that show how to pass query parameters. It should be `this.router.navigate(['/products'], {queryParams: {filterBy: 'x', showImage: true}});` – Egel Sep 22 '17 at 14:17
  • You are correct @Egel. I'll update the screen shots. – DeborahK Dec 08 '17 at 08:25
  • passing data through shared service doesn't work if the page is refreshed. the data gets undefined – Vivek Feb 14 '18 at 06:13
  • It does if you register the service in a module, NOT in a component. I have an example that demonstrates it here: https://github.com/DeborahK/MovieHunter – DeborahK Feb 14 '18 at 16:34
  • Also worth noting that option 2 tries to serialize everything to the url, so some complex objects are lost (I had an object array get turned into `[object Object],[object Object],[object Object]`). It seems a service is your only choice in this case. – matmo Feb 22 '18 at 01:08
  • This seems really stupid on Angular's part. Sometimes developers want to display a message to their user when they change paths. Putting the message in the URL could lead to all sorts of hacks and social engineering opportunities – CodyBugstein Apr 24 '18 at 03:16
  • That's why they provided Option #4. :-) You can always build a service to retain any values you need. Any component can inject and access those values throughout the application. And then it is not on the URL. – DeborahK Apr 24 '18 at 06:33
  • is there any way to hide parameters – MeVimalkumar Apr 24 '18 at 07:32
  • @DeborahK Could you explain shortly why a Shared Service wouldn't be re instantiated upon page a refresh ? I thought the only way around this was using local storage ? I ran your code, but the data is not really 'shared' as the component refetches data upon refresh, via an http call - If I am not mistaken. – Standaa - Remember Monica May 01 '18 at 22:34
  • 3
    The data is only "shared" within the executing application. If the user refreshes the page, the entire application is reloaded from the server, so no prior state is retained in the application. Thinking about it in terms of a normal application, when a user refreshes it is like closing and reopening the application. If you need to retain state after a refresh, then you will need to store it somewhere such as local storage or on the server. – DeborahK May 02 '18 at 16:42
  • 3
    Just a small hint: `route` type is `ActivatedRoute`, not `Router`. – Arsen Khachaturyan May 18 '18 at 10:01
  • Are you referring to me? I'm curious as to why you would think that? – DeborahK Sep 02 '19 at 22:26
  • Thank you! I wish the official docs had clear examples like this. – rangfu Oct 18 '19 at 10:19
  • Don't use screenshots on SO! This is why! – lllllllllllllIllllIll Nov 14 '19 at 13:06
  • Dear @DeborahK, your Plnkr example is not working because of npm installment is failed in there. Can you please fix and let me know it works all correct? – LuDeveloper Apr 16 '20 at 05:56
  • Try this instead: https://github.com/DeborahK/Angular-Routing @LuDeveloper – DeborahK Apr 21 '20 at 06:44
  • As the accepted answer it should be nice if you'd add @Véger Lóránd his answer considering a fifth method using state. – TimNode Jun 16 '20 at 18:32
  • Is that how this is supposed to work? I should be wrapping anyone else's great answers into mine? – DeborahK Jun 16 '20 at 22:06
  • In option 4 how can I send a method? I am getting DataCloneError – umunBeing Jul 28 '21 at 08:38
  • Could you elaborate on your scenario? What are you trying to accomplish? – DeborahK Jul 28 '21 at 14:55
  • I'm getting this error on implementing method 2 - ```Cannot match any routes. URL Segment: 'movies;title=ring'```. – Mayank Kataria Aug 14 '21 at 06:05
  • This is what I was looking for. Thanks for sharing @DeborahK – Muqarram Nov 02 '21 at 11:18
376

There is a new method what came with Angular 7.2.0

https://angular.io/api/router/NavigationExtras#state

Send:

    this.router.navigate(['action-selection'], { state: { example: 'bar' } });

Receive:

    constructor(private router: Router) {
      console.log(this.router.getCurrentNavigation().extras.state.example); // should log out 'bar'
    }

You can find some additional info here:

https://github.com/angular/angular/pull/27198

The link above contains this example which can be useful: https://stackblitz.com/edit/angular-bupuzn

Akash Kumar Verma
  • 2,954
  • 2
  • 14
  • 27
Véger Lóránd
  • 4,077
  • 1
  • 11
  • 13
  • 28
    This is the correct answer given the new features in Angular 7. – Randy Feb 05 '19 at 02:35
  • 4
    With this approach, how would I handle a browser refresh by the user? In that case the data in the navigation extras seems to go away, so there is no chance to use it again on refresh. – tobi_b Feb 06 '19 at 09:32
  • 1
    @tobi_b I think you are right, after refresh you can not reach it. If you need it after refresh, methods in the accepted answer will be better. – Véger Lóránd Feb 12 '19 at 14:09
  • ProTip: See the stackblitz in the answer to get this to work. – P.Brian.Mackey Feb 28 '19 at 18:46
  • Reading the pull for this, it isn't clear to me that this is intended to replace the paramMap method, From the pull author: getCurrentNavigation() will return the currently executing navigation. It will return null if there is no currently executing navigation (in other words, the application is in a stable state). – IrishDubGuy Mar 28 '19 at 14:23
  • 8
    Yep that is why you only can get the data from the this.router.getCurrentNavigation() in the constructor. If you need it elsewhere like inside ngOnInit() you can access the data trough "history.state". From the documentation: "State passed to any navigation. This value will be accessible through the extras object returned from router.getCurrentNavigation() while a navigation is executing. Once a navigation completes, this value will be written to history.state when the location.go or location.replaceState method is called before activating of this route." – Véger Lóránd Apr 01 '19 at 07:16
  • 31
    Also make sure you don't try to recieve an extras object in `ngOnInit()` as `this.router.getCurrentNavigation().extras` – hastrb Apr 15 '19 at 09:41
  • What if are navigation to external url as route.navigate(['/externalUrlRedirect', {externalUrl: 'http://google.com'}], {state: {data{name:'mayank'}}}); than how to receive the same at other side . I had tried history.state but that only returns navigationId : 1 ? – Mayank Aug 09 '19 at 18:08
  • @VégerLóránd @hastrb - why can't we use this in `ngOnInit()` – Aakash Goplani Jun 04 '21 at 14:15
  • 2
    @KinleyChristian Check out this answer, if you have further questions let me know! https://stackoverflow.com/a/54891361/4222504 – Véger Lóránd Jun 07 '21 at 06:03
  • What will happen if user reloads ? Its coming undefined :'( – Piyush Sep 24 '21 at 15:46
  • Indeed, with this solution, you can not reload the page because you will lose the data. You can implement some guards to check if the data is actually there and if not (because of reloading) you just navigate back the user to that page where he can "grab" it. Here is a [video](https://www.youtube.com/watch?v=JqCG3uhZQv0) that describes very well the differences between the different solutions. Also at [15:27](https://youtu.be/JqCG3uhZQv0?t=927) the video mentions the reload problem. – Véger Lóránd Sep 27 '21 at 09:10
  • If you are using this method to pass data between components than data will not be available once you refresh the page. Since you need to read the data from browser’s history object: like history.state.data and history will be cleared on page refresh. @VégerLóránd – Muqarram Nov 02 '21 at 11:14
  • @Amir Yes this is what I have said in my previous comment – Véger Lóránd Nov 03 '21 at 10:12
62

Latest version of angular (7.2 +) now has the option to pass additional information using NavigationExtras.

Home component

import {
  Router,
  NavigationExtras
} from '@angular/router';
const navigationExtras: NavigationExtras = {
  state: {
    transd: 'TRANS001',
    workQueue: false,
    services: 10,
    code: '003'
  }
};
this.router.navigate(['newComponent'], navigationExtras);

newComponent

test: string;
constructor(private router: Router) {
  const navigation = this.router.getCurrentNavigation();
  const state = navigation.extras.state as {
    transId: string,
    workQueue: boolean,
    services: number,
    code: string
  };
  this.test = "Transaction Key:" + state.transId + "<br /> Configured:" + state.workQueue + "<br /> Services:" + state.services + "<br /> Code: " + state.code;
}

Output

enter image description here

Hope this would help!

dev-nish
  • 691
  • 6
  • 4
  • 6
    I keep getting "navigation is null". I have tried several examples... – AppDreamer Nov 19 '20 at 03:03
  • 10
    This is old, but for future visitors – you _have_ to call it inside the constructor. https://stackoverflow.com/a/54891361/2950032 – maazadeeb Apr 28 '21 at 00:48
  • Can you still access the state data after a page refresh? – Sofia Jul 02 '21 at 15:31
  • ok I just tested this myself, and it works perfectly only directly after routing to the new component from the old one. Once you reload the page, the state is undefined : ( – Sofia Jul 02 '21 at 15:49
  • This works perfectly till the user reload the page. Then state will be undefined. :( – Piyush Sep 24 '21 at 15:42
1

@dev-nish Your code works with little tweaks in them. make the

const navigationExtras: NavigationExtras = {
  state: {
    transd: 'TRANS001',
    workQueue: false,
    services: 10,
    code: '003'
  }
};

into

let navigationExtras: NavigationExtras = {
  state: {
    transd: '',
    workQueue: ,
    services: ,
    code: ''
  }
};

then if you want to specifically sent a type of data, for example, JSON as a result of a form fill you can send the data in the same way as explained before.

1

In navigateExtra we can pass only some specific name as argument otherwise it showing error like below: For Ex- Here I want to pass customer key in router navigate and I pass like this-

this.Router.navigate(['componentname'],{cuskey: {customerkey:response.key}});

but it showing some error like below:

Argument of type '{ cuskey: { customerkey: any; }; }' is not assignable to parameter of type 'NavigationExtras'.
  Object literal may only specify known properties, and 'cuskey' does not exist in type 'NavigationExt## Heading ##ras'

.

Solution: we have to write like this:

this.Router.navigate(['componentname'],{state: {customerkey:response.key}});
Yucel Bayram
  • 1,621
  • 2
  • 22
  • 40
1

I needed access to the data in CustomRouteReuseStrategy and I couldn't inject the Router there due to a circular dependency but you can use the Location object to read the state as well.

Send:

    this.router.navigate(['action-selection'], { state: { example: 'bar' } });

Receive:
    import { Location } from '@angular/common';

    constructor(private location: Location) {
      console.log(this.location.getState().example); // should log out 'bar'
    }
AliF50
  • 13,496
  • 1
  • 15
  • 28
-9

Best I found on internet for this is ngx-navigation-with-data. It is very simple and good for navigation the data from one component to another component. You have to just import the component class and use it in very simple way. Suppose you have home and about component and want to send data then

HOME COMPONENT

import { Component, OnInit } from '@angular/core';
import { NgxNavigationWithDataComponent } from 'ngx-navigation-with-data';

@Component({
 selector: 'app-home',
 templateUrl: './home.component.html',
 styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

constructor(public navCtrl: NgxNavigationWithDataComponent) { }

 ngOnInit() {
 }

 navigateToABout() {
  this.navCtrl.navigate('about', {name:"virendta"});
 }

}

ABOUT COMPONENT

import { Component, OnInit } from '@angular/core';
import { NgxNavigationWithDataComponent } from 'ngx-navigation-with-data';

@Component({
 selector: 'app-about',
 templateUrl: './about.component.html',
 styleUrls: ['./about.component.css']
})
export class AboutComponent implements OnInit {

 constructor(public navCtrl: NgxNavigationWithDataComponent) {
  console.log(this.navCtrl.get('name')); // it will console Virendra
  console.log(this.navCtrl.data); // it will console whole data object here
 }

 ngOnInit() {
 }

}

For any query follow https://www.npmjs.com/package/ngx-navigation-with-data

Comment down for help.

Community
  • 1
  • 1
Virendra Yadav
  • 382
  • 2
  • 8