Eric Liprandi
Eric Liprandi

Reputation: 5574

How do I share information with child routes in Angular 2?

I have an application which routes would look like this:

/:partner/login
/:partner/tools
/:partner/other

Currently using 2.0.0-rc.5, I can quite simply build routes that look exactly as above. However, a downside of this approach is that each component has to extract the partner parameter on its own. So the login path declaration would look like:

{
    path: ':partner/login',
    component: LoginComponent
}

And the LoginComponent would look like:

export class LoginComponent implements OnInit {
    partner: string;
    constructor(private _route: ActivatedRoute) { }

    ngOnInit() {
        this._route.params.forEach(p => {
            this.partner = p[`partner`];
        });
    }
}

While this is manageable with 3 routes, conceptually, what I really want to say is that I have a PartnerComponent which has child routes login, tools, etc. The routing would look like this:

{ path: ':partner', component: PartnerComponent
    children: [
        { path: 'login', component: LoginComponent},
        { path: 'tools', component: ToolsComponent}
    ]
 }

And using TypeScript's inheritance, I can create a base component for each child like:

export class BaseComponent implements OnInit {
    partner: string;
    constructor(private _route: ActivatedRoute) { }

    ngOnInit() {
        this._route.parent.params.forEach(p => {
            this.partner = p[`partner`];
        });
    }
}

and child components would look like:

export class LoginComponent extends BaseComponent {
    constructor(route: ActivatedRoute) {
        super(route);
    }

    ngOnInit() {
        super.ngOnInit();
    }
}

While the above works, it feels a bit dirty to look up the parent route. I know if I change the hierarchy, I only need to change it in the base, but still

Is there a cleaner way to share information between a parent and its child route components.

If it were a more traditional parent element/child element relationship, we would simply use data binding between the two to pass that information.

Upvotes: 6

Views: 1772

Answers (2)

yorch
yorch

Reputation: 7318

What you can do is to use a Resolve guard for your parent route, so the data will be loaded for any :partner route.

A Resolve would look like:

import { Injectable }             from '@angular/core';
import { Router, Resolve,
         ActivatedRouteSnapshot } from '@angular/router';

import { Partner } from './partner.model';
import { Api } from './api.service';

@Injectable()
export class PartnerResolve implements Resolve<Partner> {
  constructor(private api: Api,
              private router: Router) {}

  resolve(route: ActivatedRouteSnapshot): Observable<Partner> {
    let id = +route.params['partner'];

    return this.api.getPartner(id);
  }
}

Then, your route would need to include the PartnerResolve so it would not load until the data was requested and it's available:

{
  path: ':partner', component: PartnerComponent,
  resolve: {
    partner: PartnerResolve
  },
  children: [
    { path: 'login', component: LoginComponent},
    { path: 'tools', component: ToolsComponent},
  ]
}

And your PartnerComponent would just get it with:

ngOnInit() {
  this.route.data.forEach((data: { partner: Partner }) => {
    this.partner = data.partner;
  });
}

And your child components would use:

ngOnInit() {
  this.route.parent.data.forEach((data: { partner: Partner }) => {
    this.partner = data.partner;
  });
}

Upvotes: 4

Kevin Le
Kevin Le

Reputation: 856

Another way to pass data from the parent to the child is to use @Input.

@Component({
   selector: 'partner',
   template: 'partner.html'
   directives: [LoginComponent]
})
export class PartnerComponent {
   partner: string;
}

@Component({
   selector: 'login',
   template: 'login.html'
})
export class LoginComponent {
   @Input() loginPartner: string; //passed in from the parent
}

//partner.html
<div>
   <login [login-partner]='partner'></login>
</div>

Reference https://angular.io/docs/ts/latest/cookbook/component-communication.html

Upvotes: -1

Related Questions