Reputation: 605
I need to pass data from one component to another, I found only the way to do it with route parameters in url:
So I have such configuration for target component in router:
{
path: 'edit-tags/:type/:name/:id',
component: EditTagsComponent,
},
And I use it like that from another component:
this.router.navigate([`../edit-tags/${product.type}/${product.name}/${product.id}`], { relativeTo: this.route });
It works ok, but I don't want to show id
in url and also need to pass some more data to the component.
Also I've seen using configurations like that in router:
{ path: 'test-product', component: ProductsContentComponent, data: { role: 'admin', type: 'test-product' } }
But I haven't found an example of using the same approach inside another component.
So, is there a way to pass some data from component to component on routing without reflecting it in url?
Upvotes: 5
Views: 8161
Reputation: 2753
We needed the same solution for our web app and we took the approach of passing data from one component to another through a service. This way, sensitive data is not expressed in the URL. Here is our first component that shows a list of data. The main method we are focusing on is the changeRoute method. Prior to route change, we save the currently selected data to the dataService and then perform a route change.
import { Component, OnInit } from "@angular/core";
import { Router } from "@angular/router";
import { DataService } from "./data.service";
import { Data } from "../../models/data.model";
@Component({
selector: "ei-data-list",
template: require("./data-list.component.html")
})
export class DataListComponent implements OnInit {
constructor(private dataService: DataService, private router: Router) {}
// .... code for properties and getting data here
changeRoute(data: Data) {
this.dataService.data = data;
this.router.navigate(["/data-list/data-item"]);
}
}
Here is the data service that we built. For this example we trimmed it down a bit.
import { Injectable } from "@angular/core";
import { Data } from "../../models/data.model";
@Injectable()
export class DataService {
constructor() { }
public data: Data;
}
Finally we have our second component which we are passing the data. Inside the ngOnInit, we are gathering the data so it is ready when the page loads. I hope this helps.
import { Component } from "@angular/core";
import { DataService } from "./data.service";
@Component({
selector: "ei-data-item",
template: require("./data.component.html")
})
export class DataComponent {
constructor(private dataService: DataService) {}
data: Data;
ngOnInit() {
this.data = this.dataService.data;
}
}
Upvotes: 6
Reputation: 5454
Another way to do this is with a subject and a subscription from a common service between the two components. I do this all the time for search terms following the pattern described here.
In your service, you'd have something like:
export class MyService {
private searchStringSubject = new Subject<string>();
searchAnnounced$ = this.searchStringSubject.asObservable();
announceSearch(searchValue: string) {
this.searchStringSubject.next(searchValue);
}
...
}
And in your parent component have the event drive the data:
public onSelectSearchValue(e: TypeaheadMatch): void {
this.chipService.announceSearch(e.item.id);
}
And in your child component, have it subscribe to the data:
export class ChildComponent implements OnInit { subscription: Subscription; id: string;
constructor(private _service: MyService) {
this.subscription = _service.searchAnnounced$.subscribe(
id => {
this.id = id;
this.query();
});
}
Upvotes: 0