How do I pass data to Angular routed components?

dragonmnl picture dragonmnl · Apr 25, 2016 · Viewed 456.9k times · Source

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

Answer

G&#252;nter Z&#246;chbauer picture Günter Zöchbauer · Apr 25, 2016

update 4.0.0

See Angular docs for more details https://angular.io/guide/router#fetch-data-before-navigating

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 also https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#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 at https://github.com/angular/angular/issues/9757#issuecomment-229847781