Angular2 pass data to route from component

8.1k views Asked by At

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?

2

There are 2 answers

4
aholtry On BEST ANSWER

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;
    }
}
0
occasl On

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();
        });

}