How do I pass data to Angular routed components?
Asked Answered
D

21

422

In one of my Angular 2 routes's templates (FirstComponent) I have a button

first.component.html

<div class="button" click="routeWithData()">Pass data and route</div>

My goal is to achieve:

Button click -> route to another component while preserving data and without using the other component as a directive.

This is what I tried...

1ST APPROACH

In the same view I am storing collecting same data based on user interaction.

first.component.ts

export class FirstComponent {
     constructor(private _router: Router) { }

     property1: number;
     property2: string;
     property3: TypeXY; // this a class, not a primitive type

    // here some class methods set the properties above

    // DOM events
    routeWithData(){
         // here route
    }
}

Normally I'd route to SecondComponent by

 this._router.navigate(['SecondComponent']);

eventually passing the data by

 this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);

whereas the definition of the link with parameters would be

@RouteConfig([
      // ...
      { path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent} 
)]

The issue with this approach is that I guess I can't pass complex data (e.g. an object like property3) in-url;

2ND APPROACH

An alternative would be including SecondComponent as directive in FirstComponent.

  <SecondComponent [p3]="property3"></SecondComponent>

However I want to route to that component, not include it!

3RD APPROACH

The most viable solution I see here would be to use a Service (e.g. FirstComponentService) to

  • store the data (_firstComponentService.storeData()) on routeWithData() in FirstComponent
  • retrieve the data (_firstComponentService.retrieveData()) in ngOnInit() in SecondComponent

While this approach seems perfectly viable, I wonder whether this is the easiest / most elegant way to achieve the goal.

In general I'd like to know whether I'm missing other potential approaches to pass the data between components, particularly with the less possible amount of code

Dinnerware answered 25/4, 2016 at 8:10 Comment(4)
thanks @Prashobh. Pass data using Query Parameters is what i was looking for. your link saved my day.Astraphobia
Angular 7.2 has now new feature to pass data between routes using state check the PR for more details. Some useful information hereImmeasurable
@Prashobh Thanks a lot. The link which you have shared is very usefulIndrawn
Routing is a complex feature in Angular and definitely worth learning! Here you may find interesting details about passing data via the routing: indepth.dev/tutorials/angular/… This guide goes through various techniques about using static data in routing definition and dynamic data (state) during specific navigation.Westfall
B
306

Update 4.0.0

See Angular Angular Router - Fetch data before navigating for more details.

Original

Using a service is the way to go. In route params you should only pass data that you want to be reflected in the browser URL bar.

See Angular Angular Cookbook Component Communication - Bidirectional Service.

The router shipped with RC.4 re-introduces data

constructor(private route: ActivatedRoute) {}
const routes: RouterConfig = [
  {path: '', redirectTo: '/heroes', pathMatch: 'full'},
  {path: 'heroes', component: HeroDetailComponent, data: {some_data: 'some value'}}
];
class HeroDetailComponent {
  ngOnInit() {
    this.sub = this.route
      .data
      .subscribe(v => console.log(v));
  }

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

See also the Plunker.

Ballade answered 25/4, 2016 at 8:12 Comment(21)
thanks for the answer. I had a look at the docs. Can you please clarify when I should opt for observables and when just set attributes using a set/get method in the service?Dinnerware
Observables allow interested components to subscribe to changes. With properties you need to poll ({{myService.someProp}} is recognized and updated by Angulars change detection though). If you want to switch to the way more performant OnPush change detection strategy Observables have a strong advantage because then your code depends on being notified about changes so your code can invoke change detection.Knocker
Is this answer still valid for Angular 2.1.0 ?Malraux
RC.4 router data is only for static data. You can not send different data to the same route it always has to be the same data am I wrong?Fleda
If you use a resolver, then you get the data the resolver returns.Knocker
Is there a way to ensure the data has been stored before retrieving it? For example in the OP situation, not loading SecondComponent until a good response from the store data has been received. Otherwise SecondComponent would be emptyReminiscent
I guess it would be better to create a new question with more details (some code). I don't really get what you try to accomplish.Knocker
@GünterZöchbauer I am a bit confused... i have 3 components which use same data but how can i update the data in all 3 components if the data is changed by 1 of the 3 components... 1 is app component 1 is popup component which is inside app component..i can exchange data thr.. i can pass data to router-outlet by using service but if after passing data..the data is changed by popup component..it wont change in router-outlet component..how can i update data thr??Cushman
@HimanshuBansal please create a new question with the code that demonstrates what you try to accomplishKnocker
Is it possible to pass data during navigate instead of in the router as described in this answer? Example, this.router.navigate(['/apply', res.loanApplicationId, data{}]);Chromosome
No, use a shared service for this use case.Knocker
How to get that 'some value'. getting an array in this.subNigercongo
@Nigercongo sorry, I don't understand the question. I'd suggest you create a new question that contains your code and more details about what you try to accomplish.Knocker
In Angular 5, anyway, you should be able to ... ngOnInit() { this.myVar = this.route.snapshot.data['some_data']; }Progestin
how to pass dynamic json?Absolutely
@bhaumikshah use a shared service.Knocker
@GünterZöchbauer is there any example for reference?Absolutely
Injecting a service is an effective hack that dates back to the first release of the framework and continues to this day. This approach also stinks to high heaven. Components should not be wired for eternity to services. That's what @input is designed for.Gibberish
@RickO'Shea that's clearly wrong. Services can be configured by providers at any parent level and are therefore much more flexible with less coupling than inputs. Routed components don't support values being passed through inputs anyway.Knocker
If you're able to use Angular v7.2 it allows for passing state now in the router using the NavigationExtras - https://mcmap.net/q/87208/-angular-passing-data-between-routesLeaseholder
sadly, this doesnt work anymore (checked on angular 10) - you can pass data in route config, but not get it in cmp like in Gunther's answer above. But you can use this: this.router.events.subscribe((data) => { if (data instanceof RoutesRecognized) { const passedData = data.state.root.firstChild.data.passedData; } });Tolley
I
83

I think since we don't have $rootScope kind of thing in angular 2 as in angular 1.x. We can use angular 2 shared service/class while in ngOnDestroy pass data to service and after routing take the data from the service in ngOnInit function:

Here I am using DataService to share hero object:

import { Hero } from './hero';
export class DataService {
  public hero: Hero;
}

Pass object from first page component:

 ngOnDestroy() {
    this.dataService.hero = this.hero; 
 }

Take object from second page component:

 ngOnInit() {
    this.hero = this.dataService.hero; 
 }

Here is an example: plunker

Isadoraisadore answered 19/9, 2016 at 9:39 Comment(7)
This is beautiful, but how common in the Ng2 community is this? I can't recall reading it in the docs...Waterman
Comparing to other option like url parameters or other browser storage this seems to me better. I also did not see in any documentation to work like this.Isadoraisadore
Does it work when the user opens a new tab and copy paste the second component route? Can I able to fetch this.hero = this.dataService.hero? Will I get the values?Reinold
This is indeed very simple and every Angular developer knows but problem is once you refresh you loose data in the services. User will have to do all stuffs again.Objectionable
@SantoshKadam the question is "How do I pass data to Angular routed components?" so passing data by ngOnDestroy and ngOnInit functions is a way, and always simple is the best. If user needs to get data after reload then there need to save data in a permanent storage and read again from that storage.Isadoraisadore
Warning! If you use this method and make refresh of the page, the data from the service will be deleted! Its better to store the values in a databaseEpicanthus
Where did you got the attribute dataService?Shaunta
M
83

Angular 7.2.0 introduced new way of passing the data when navigating between routed components:

@Component({
  template: `<a (click)="navigateWithState()">Go</a>`,
})
export class AppComponent  {
  constructor(public router: Router) {}
  navigateWithState() {
    this.router.navigateByUrl('/123', { state: { hello: 'world' } });
  }
}

Or:

@Component({
  selector: 'my-app',
  template: `
  <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>`,
})
export class AppComponent  {}

To read the state, you can access window.history.state property after the navigation has finished:

export class PageComponent implements OnInit {
  state$: Observable<object>;

  constructor(public activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.state$ = this.activatedRoute.paramMap
      .pipe(map(() => window.history.state))
  }
}
Mondrian answered 27/6, 2019 at 14:29 Comment(11)
does not work for me, window.history.state returns something like {navigationId: 2} instead of returning the object I passed-in.Heliozoan
@Heliozoan which Angular version are you using?Mondrian
I am using angular version 8.1.0Heliozoan
I'm seeing the same thing as Louis, with a lower version than his but still high enough that it's supposed to have that feature.Schedule
as part of the returned object, navigationId with a value is added. If no data is added, only the navigationId will be shown. Be see the passed data, go back or refresh your app and re-trigger the action that adds the data to the route and navigates to the next route (eg. button click). This will then add your data to the object.Alejoa
After refreshing, the data gets cleared. You should store the data somewhere temporarily if you want it to be available after refresh.Brittain
use { state: {data: {hello: 'world'}} } instead { state: { hello: 'world' } } to avoid navigationId ... restore it by history.state.dataCaltrop
There is a 640k data size browser limit on the state object. #24426385Derision
@Heliozoan I played around with the setting of state and it looks like "navigationId" is a reserved key that cannot be set using navigateByUrl(). If you change the name of the key that you set in the "state" node to something like "navigation_id", you will then get window.history.state to return {navigation_id: <real navigation Id from object>, navigationId: 2}.Vaughnvaught
try following this article. it works good for me. it uses history.state instead. medium.com/ableneo/…Alejandraalejandrina
this.router.navigate(['/123'], { state: { hello: 'world' } }); should workCompanionable
S
48
<div class="button" click="routeWithData()">Pass data and route</div>

well the easiest way to do it in angular 6 or other versions I hope is to simply to define your path with the amount of data you want to pass

{path: 'detailView/:id', component: DetailedViewComponent}

as you can see from my routes definition, I have added the /:id to stand to the data I want to pass to the component via router navigation. Therefore your code will look like

<a class="btn btn-white-view" [routerLink]="[ '/detailView',list.id]">view</a>

in order to read the id on the component, just import ActivatedRoute like

import { ActivatedRoute } from '@angular/router'

and on the ngOnInit is where you retrieve the data

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

you can read more in this article https://www.tektutorialshub.com/angular-passing-parameters-to-route/

Strepphon answered 6/9, 2018 at 14:2 Comment(3)
what if i want to send a complex object? i don't want to bloat my routes to unmaintainable nonsense :(Burnoose
@Burnoose Use a shared service then.Souvenir
@Burnoose the idea with sending only the id or a simple string as data is to make the URL more 'sharable' and easily crawlable by bots etc. So that the resultant link can be shared by users of your app. For sending bigger objects, a service will be more effective.Nabalas
W
38

I looked at every solution (and tried a few) from this page but I was not convinced that we have to kind of implement a hack-ish way to achieve the data transfer between route.

Another problem with simple history.state is that if you are passing an instance of a particular class in the state object, it will not be the instance while receiving it. But it will be a plain simple JavaScript object.

So in my Angular v10 (Ionic v5) application, I did this-

this.router.navigateByUrl('/authenticate/username', {
    state: {user: new User(), foo: 'bar'}
});

enter image description here

And in the navigating component ('/authenticate/username'), in ngOnInit() method, I printed the data with this.router.getCurrentNavigation().extras.state-

ngOnInit() {
    console.log('>>authenticate-username:41:',
        this.router.getCurrentNavigation().extras.state);
}

enter image description here

And I got the desired data which was passed-

enter image description here

Wahkuna answered 10/8, 2020 at 4:32 Comment(13)
extras ? is that something you just defined or an angular property?Newsmagazine
That's a property from Angular.Wahkuna
exactly what i was looking for thanks mate..here is the upvote for you ;) I am also using it in ionic5 projPeplos
@Peplos Yes, I'm also using it in Ionic. That's where I dug into Angular.Wahkuna
Just a doubt. I am able to pass data.. but if I have to pass instance of inappbrowser to different module..its not able to serialise and threw error? Any idea other way?I don't really want to import whole module in my page just for one inappbrowserPeplos
In that case, the only way is to use the service reference. Basically, define a global service and use its scope to pass the reference. Or else you can use observables/subject as well.Wahkuna
Wonderful answer! It's important to remember that accessing the state (after routing to the new page) only worked on the constructor for me, and not inside the ngOnInit. That's because the getCurrentNavigation() was null.Volpe
That's working fine for us. What's your Angular version @Itay?Wahkuna
@Volpe I agree. I am using Angular 11. Current navigation scope is ended before ngOnInit(). So I had to take the state value from constructor.Inference
Data is lost if page is refreshedShyamal
Yes, of course. That is supposed to get lost. You need to implement the caching on your own if it is a requirement.Wahkuna
it worked for me ONLY after i moved the code from ngOnInit to constructorUrbanity
@OjonugwaJudeOchalifu data is lost because it is not stored into the URL (queryParams). Please vote up this issue for the angular team to support storing JSON objects in urlsFante
F
25

It is 2019 and many of the answers here would work, depending on what you want to do. If you want to pass in some internal state not visible in URL (params, query) you can use state since 7.2 (as I have learned just today :) ).

From the blog (credits Tomasz Kula) - you navigate to route....

...from ts: this.router.navigateByUrl('/details', { state: { hello: 'world' } });

...from HTML template: <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>

And to pick it up in the target component:

constructor(public activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.state$ = this.activatedRoute.paramMap
      .pipe(map(() => window.history.state))
  }

Late, but hope this helps someone with recent Angular.

Formalism answered 11/11, 2019 at 11:29 Comment(2)
Isn't state lost when user refreshes? It would be fun to be able to persist it natively.Alyciaalyda
This is literally the only way that worked for me. Thanks 👍Votive
F
21

I this the other approach not good for this issue. I thing the best approach is Query-Parameter by Router angular that have 2 way:

Passing query parameter directly

With this code you can navigate to url by params in your html code:

<a [routerLink]="['customer-service']" [queryParams]="{ serviceId: 99 }"></a>

Passing query parameter by Router

You have to inject the router within your constructor like:

constructor(private router:Router){

}

Now use of that like:

goToPage(pageNum) {
    this.router.navigate(['/product-list'], { queryParams: { serviceId: serviceId} });
}

Now if you want to read from Router in another Component you have to use of ActivatedRoute like:

constructor(private activateRouter:ActivatedRouter){

}

and subscribe that:

  ngOnInit() {
    this.sub = this.route
      .queryParams
      .subscribe(params => {
        // Defaults to 0 if no query param provided.
        this.page = +params['serviceId'] || 0;
      });
  }
Faintheart answered 7/1, 2019 at 8:11 Comment(1)
this.router.navigate(['/product-list'], { queryParams: { serviceId: serviceId} }); can be replaced with this.router.navigate(['/product-list'], { queryParams: { serviceId} });Reuven
N
21

Some super smart person (tmburnell) that is not me suggests re-writing the route data:

let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');

As seen here in the comments.

I hope someone will find this useful

Neurology answered 13/1, 2019 at 17:44 Comment(1)
just found out about this and i feel like i need some stackoverflow points :)Lanark
F
17

Solution with ActiveRoute (if you want pass object by route - use JSON.stringfy/JSON.parse):

Prepare object before sending:

export class AdminUserListComponent {

  users : User[];

  constructor( private router : Router) { }

  modifyUser(i) {

    let navigationExtras: NavigationExtras = {
      queryParams: {
          "user": JSON.stringify(this.users[i])
      }
    };

    this.router.navigate(["admin/user/edit"],  navigationExtras);
  }

}

Receive your object in destination component:

export class AdminUserEditComponent  {

  userWithRole: UserWithRole;      

  constructor( private route: ActivatedRoute) {}

  ngOnInit(): void {
    super.ngOnInit();

      this.route.queryParams.subscribe(params => {
        this.userWithRole.user = JSON.parse(params["user"]);
      });
  }

}
Footboard answered 20/9, 2018 at 20:2 Comment(7)
That works, but what if I do not want to expose all data in the URL?Kerwon
You can encrypt data put it into params, after that encrypt in target component.Footboard
I've created the service for data sharing.Kerwon
What is that super.ngOnInit(); for?Thermopile
Thank you. JSON.stringify() on the sending side and JSON.parse() on the receiving side worked for me.Catherin
was forced to do JSON.stringify(user).toString() and then parse the result to queryParams: { 'user': [result here] }Herewith
Best and working solution after trying a few other solutions hereSeftton
A
11

Routes:

{ path: 'foo-route', component: FooComponent, data: { myData: false } },

In component access the data object once:

pipe(take(1)) unsubsrcibes immediately so there is no memory leak and no need to manually unsubscribe

constructor(private activatedRoute: ActivatedRoute) { ... }

ngOnInit(): void {
  this.activatedRoute.data.pipe(take(1)).subscribe((data) => {
    console.log(data); // do something with the data
  });
}
  • remember to import needed stuff

Edit: the new firstValueFrom() could be better

Arboriculture answered 1/4, 2021 at 10:19 Comment(0)
O
5

3rd approach is most common way to share data between components. you may inject the item service which you want to use in related component.

import { Injectable } from '@angular/core';
import { Predicate } from '../interfaces'

import * as _ from 'lodash';

@Injectable()
export class ItemsService {

    constructor() { }


    removeItemFromArray<T>(array: Array<T>, item: any) {
        _.remove(array, function (current) {
            //console.log(current);
            return JSON.stringify(current) === JSON.stringify(item);
        });
    }

    removeItems<T>(array: Array<T>, predicate: Predicate<T>) {
        _.remove(array, predicate);
    }

    setItem<T>(array: Array<T>, predicate: Predicate<T>, item: T) {
        var _oldItem = _.find(array, predicate);
        if(_oldItem){
            var index = _.indexOf(array, _oldItem);
            array.splice(index, 1, item);
        } else {
            array.push(item);
        }
    }


    addItemToStart<T>(array: Array<T>, item: any) {
        array.splice(0, 0, item);
    }


    getPropertyValues<T, R>(array: Array<T>, property : string) : R
    {
        var result = _.map(array, property);
        return <R><any>result;
    }

    getSerialized<T>(arg: any): T {
        return <T>JSON.parse(JSON.stringify(arg));
    }
}



export interface Predicate<T> {
    (item: T): boolean
}
Outfitter answered 30/10, 2016 at 19:38 Comment(3)
The service gets instantiated when switching routes. So you loose dataChristinchristina
@JimmyKane You speaking about specifically when the page refreshes but if it doesn't refresh then the memory is still saved in a service. This should be the default behaviour since it will save loading many times.Butterball
@AaronRabinowitz right. Sorry for the confusion. And sorry for the down vote. Wish I could undo it now. Too late. Was new to angular 2 and my problem with trying your approach was that I had the service provided to many components and not provided via the app module.Christinchristina
S
3

Pass using JSON

  <a routerLink = "/link"
   [queryParams] = "{parameterName: objectToPass| json }">
         sample Link                   
  </a>
Screwed answered 19/6, 2018 at 0:6 Comment(2)
This would be a better answer if you could show how the parameter is consumed in the receiving component as well - the whole route that it takes. Meaning if someone does not know how to pass a parameter, he is also not going to know how to use this parameter in the receiving component. :)Waterman
A disadvantage to this is there's a size limitation to the querystring and sometimes you don't want object properties visible in the address bar.Ceramal
P
3

use a shared service to store data with a custom index. then send that custom index with queryParam. this approach is more flexible.

// component-a : typeScript :
constructor( private DataCollector: DataCollectorService ) {}

ngOnInit() {
    this.DataCollector['someDataIndex'] = data;
}

// component-a : html :
<a routerLink="/target-page" 
   [queryParams]="{index: 'someDataIndex'}"></a>

.

// component-b : typeScript :
public data;

constructor( private DataCollector: DataCollectorService ) {}

ngOnInit() {
    this.route.queryParams.subscribe(
        (queryParams: Params) => {
            this.data = this.DataCollector[queryParams['index']];
        }
    );
}
Poling answered 24/12, 2018 at 10:46 Comment(0)
K
2

say you have

  1. component1.ts
  2. component1.html

and you want to pass data to component2.ts.

  • in component1.ts is a variable with data say

      //component1.ts
      item={name:"Nelson", bankAccount:"1 million dollars"}
    
      //component1.html
       //the line routerLink="/meter-readings/{{item.meterReadingId}}" has nothing to 
      //do with this , replace that with the url you are navigating to
      <a
        mat-button
        [queryParams]="{ params: item | json}"
        routerLink="/meter-readings/{{item.meterReadingId}}"
        routerLinkActive="router-link-active">
        View
      </a>
    
      //component2.ts
      import { ActivatedRoute} from "@angular/router";
      import 'rxjs/add/operator/filter';
    
      /*class name etc and class boiler plate */
      data:any //will hold our final object that we passed 
      constructor(
      private route: ActivatedRoute,
      ) {}
    
     ngOnInit() {
    
     this.route.queryParams
      .filter(params => params.reading)
      .subscribe(params => {
      console.log(params); // DATA WILL BE A JSON STRING- WE PARSE TO GET BACK OUR 
                           //OBJECT
    
      this.data = JSON.parse(params.item) ;
    
      console.log(this.data,'PASSED DATA'); //Gives {name:"Nelson", bankAccount:"1 
                                            //million dollars"}
       });
      }
    
Kolosick answered 13/5, 2019 at 18:31 Comment(0)
I
2

You can use BehaviorSubject for sharing data between routed components. A BehaviorSubject holds one value. When it is subscribed it emits the value immediately. A Subject doesn't hold a value.

In the service.

@Injectable({
  providedIn: 'root'
})
export class CustomerReportService extends BaseService {
  reportFilter = new BehaviorSubject<ReportFilterVM>(null);
  constructor(private httpClient: HttpClient) { super(); }

  getCustomerBalanceDetails(reportFilter: ReportFilterVM): Observable<Array<CustomerBalanceDetailVM>> {
    return this.httpClient.post<Array<CustomerBalanceDetailVM>>(this.apiBaseURL + 'CustomerReport/CustomerBalanceDetail', reportFilter);
  }
}

In the component you can subscribe to this BehaviorSubject.

this.reportService.reportFilter.subscribe(f => {
      if (f) {
        this.reportFilter = f;
      }
    });

Note: Subject won't work here, Need to use Behavior Subject only.

Interclavicle answered 19/3, 2020 at 18:7 Comment(0)
B
2

By default i won't use a guard for this one for me it is more can i enter the route or can i leave it. It is not to share data betweenn them.

If you want to load data before we entered a route just add an resolver to this one this is also part of the Router.

As very basic example:

Resolver

import { Resolve, ActivatedRoute } from "@angular/router";
import { Observable } from "rxjs";
import { Injectable } from "@angular/core";
import { take } from "rxjs/operators";

@Injectable()
export class UserResolver implements Resolve<User> {

    constructor(
        private userService: UserService,
        private route: ActivatedRoute
    ) {}

    resolve(): Observable<firebase.User> {
        return this.route.params.pipe(
            switchMap((params) => this.userService.fetchUser(params.user_id)),
            take(1)
        );
    }
}

put to the router:

RouterModule.forChild([
{
    path: "user/:user_id",
    component: MyUserDetailPage,
    resolve: {
        user: UserResolver
    }
  }
}]

get the data in our component

ngOnInit() {
    const user: firebase.User = this.activatedRoute.snapshot.data.user;
}

The downside on this approach is, he will enter the route first if he get the user data not before, this ensures the data for the user has been loaded and is ready on start of the component, but you will stay on the old page as long the data has been loaded (Loading Animation)

Bonne answered 17/11, 2020 at 11:2 Comment(0)
U
1

If you want to add a parameter to the URL while navigating and simultaneously hide the data being passed to another component in the URL, you've to use both state and queryParams.

For Example: Here clicking the edit button will route to CreateEmployeeComponent with the employee data.

ViewEmployeeComponent:

editEmployee(employee) {
  this.router.navigate(['employee/create'], { queryParams: { action: 'edit' }, state: { user: this.employee } }); }

Then the URL after routing to the component will be like this:

http://localhost:4200/employee/create?action=edit

CreateEmployeeComponent

    let employeeData = history.state.user;
    console.log(employeeData);
Unreal answered 8/12, 2023 at 14:18 Comment(1)
This was very easy to implement and makes my url clean Thanks for sharingVancouver
A
0

One fine solution is to implement a Guard with canActivate method. In this scenario you can fetch data from a given api and let user access the component describe in the routing file. In the meantime one can set the data property of the route object and retrieve it in the component.

Let say you have this routing conf:

const routes: Routes = [
    { path: "/:projectName", component: ProjectComponent, canActivate: [ProjectGuard] }
]`

in your guard file you may have:

canActivate(next: ActivatedRouteSnapshot,state: RouterStateSnapshot)
: Observable<boolean> | Promise<boolean> | boolean {
return this.myProjectService.getProject(projectNameFoundElsewhere).pipe(
  map((project) => {
    if (project) {
      next.data = project;
    }
    return !!project;
  }),
);

}`

Then in your component

constructor(private route: ActivatedRoute) {
    this.route.data.subscribe((value) => (this.project = value));
}

This way is a bit different than passing via a service since service keep the value in a behaviorSubject as long as it is not unset. Passing via tha guard make the data available for the current route. I havent check if the children routes keep the data or not.

Anthonyanthophore answered 29/9, 2020 at 22:29 Comment(0)
M
0

In scenario where data needs to be passed to another Route, best and simplest solution is using { window.localStorage }. Also, do not remember to remove data from local storage once its use is over. I used ngOnDestroy's destroy() method to clean up this data. This also resolves a problem where data is lost by page refresh.

Mulvihill answered 29/3, 2021 at 21:28 Comment(1)
From Review: Could you please provide some sample code?Oletta
T
0

There are several approaches to pass data to the routed components.

One of the approach is through the 'Query Paramaeters'.

If i want to pass data of table-id from the TableReservationComponent then i can send it through query params.

TableReservationComponent.ts

TableId : number = 2;

this.router.navigate(['order'],{queryParams:{table_id : TableId}});

Now in the OrderComponent , we are able to get the table_id from the TableReservationComponent.

export class OrderComponent implements OnInit

{
    tableId : number ;

    constructor(private route: ActivatedRoute) { }

    ngOnInit(): void {
       this.route.queryParams.subscribe(params => {
       this.tableId = params['table_id'];
       
        });
    }

}

Here the table_id is coming from the TableReservationComponent in a Key Value Pair , and I can access in Order Component With the Key(params['table_id']) and I can Use the table_id in the OrderComponent

Tipi answered 25/7, 2023 at 5:41 Comment(0)
H
0

Angular 17.1 introduced new Router info parameter to NavigationExtras:

.html:

<button routerLink="home" [info]="{ hello: 'world' }">
    Home
</button>

.ts:

this.router.navigateByUrl('home', { info: { hello: 'world' } });

It's similar to state option, but it has two main differences. It's not saved in navigation history (history.state). And object is not copied or cloned, but assigned directly to the Router's current Navigation.

Homosexuality answered 10/3 at 10:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.