Joseph Girgis
Joseph Girgis

Reputation: 3165

Angular 2 how to pass variable from parent component to router outlet

All the tutorials and answers that I have found show only how to pass a variable from parent component to child component using inputs but what is this child component is contained within the router outlet and not directly in the parent template ??

e.g:

Main component

@Component({
  selector: 'my-app',
  template: `
          Main page
          <router-outlet></router-outlet>
              `,
  directives: [ROUTER_DIRECTIVES]
})

@RouteConfig([
    { path: '/contact', name: 'Contact', component: ContactComponent},
 ])

export class AppComponent{
  public num:Number = 123;
}





@Component({
   selector: 'contact-page',
   template: 'contact page'
})
export class ContactComponent{
   public num:Number;
}

So in this example the main component template contain a router outlet where the child contact component will be rendered but how can I get variable "num" value in the child component evaluated inside a router outlet from the parent app component ??

Upvotes: 8

Views: 5688

Answers (3)

DNRN
DNRN

Reputation: 2489

I just stumbled over this question, here is how I have solved similar issues.

I would use a service to solve this. Then it is possible for all children and the parent to set the property, and the changes are propagated out for all subscribers. First I would create a service with a private BehaviorSubject which have a public getter and setter, to encapsulate ReplaySubject and only return Observable:

private _property$: BehaviorSubject<number> = new BehaviorSubject(1);

set property(value: number) {
    this._property$.next(value);
}

get property$(): Observable<number> {
    return this._property$.asObservable();
}

The reason for using new BehaviorSubject(1), is to set the initial value to 1, so there is something to subscribe to.

In the parents onInit, I would se the default value of property (num):

private _propertySubscribtion: Subscription

ngOnInit() {
    // set default value to 5
    this._componentService.property = 5;

    // If property is updated outside parent
    this._componentService.property$.subscribe(p => {
        this.property = p;
    });
}

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

In one or more of of the child components, it possible to subscribe for changes:

private _propertySubscribtion: Subscription

ngOnInit() {
    this._propertySubscribtion = this._componentService.property$.subscribe(p => {
        this.property = p;
    });
}

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

And if some child or parent updates the property:

updateProperty() {
    // update property
    this._componentService.property = 8;
}

All subscribers will know about it.

Upvotes: 4

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657118

Currently you can't bind to components added by the router. Use a shared service instead (there are tons of examples here on SO already) to pass data from or to the added component or to subscribe to events.

See also this issue https://github.com/angular/angular/issues/4452 especially this comment https://github.com/angular/angular/issues/4452#issuecomment-153889558

Upvotes: 0

Sasxa
Sasxa

Reputation: 41254

If your data is immutable, you can use RouteData.

@Component({...})
@RouteConfig([
    { path: '/contact', name: 'Contact', component: ContactComponent, data: {num: 123}},
 ])
export class AppComponent {
}

@Component({...})
export class ContactComponent {
   public num:Number;
   constructor(data: RouteData) {
     this.num = data.get('num');
   }
}

Could be useful to pass some configuration options you don't want to hardcode in child routes. But if you're expecting data to change, you'll need some other method.

Upvotes: -1

Related Questions