9

Based on the docs of Angular 2 you can pass data from a component to another quite easily with the @Input.

So for example I can set the parent like this:

import { Component } from '@angular/core';
import { HEROES } from './hero';
@Component({
  selector: 'hero-parent',
  template: `
    <h2>{{master}} controls {{heroes.length}} heroes</h2>
    <hero-child *ngFor="let hero of heroes"
      [hero]="hero"
      [master]="master">
    </hero-child>
  `
})
export class HeroParentComponent {
  heroes = HEROES;
  master: string = 'Master';
}

And the get the data in the child component like this:

import { Component, Input } from '@angular/core';
import { Hero } from './hero';
@Component({
  selector: 'hero-child',
  template: `
    <h3>{{hero.name}} says:</h3>
    <p>I, {{hero.name}}, am at your service, {{masterName}}.</p>
  `
})
export class HeroChildComponent {
  @Input() hero: Hero;
  @Input('master') masterName: string;
}

So it's quite obvious, pass the [hero]="data" to the template of the parent component (of course in the child selector) and handle them into the child component.

But here's the issue.

My child component DOM element (in this case <hero-child>) is not available in the parent's template but instead it is loaded there in a <router-outlet> element.

How can I pass data then to a child route component then? Isn't the input the correct way? I want to avoid double,treble etc calls to get the same data that already have in my parent route/component.

6
  • I would use a model driven form and a service instead of template Commented Aug 31, 2016 at 14:55
  • 2
    I'm getting the data to the parent already via a service. Isn;t this what you mean? Commented Aug 31, 2016 at 14:56
  • 2
    @cport1 how model driven form could help, he wanted to pass component data to pass HeroParentComponent data to HeroChildComponent data which resides in router-outlet, Good question :) Commented Aug 31, 2016 at 14:58
  • @VassilisPits I would like to refer discussion link on this issue from github Commented Aug 31, 2016 at 15:07
  • stackoverflow.com/questions/33675155/… Commented Aug 31, 2016 at 15:11

3 Answers 3

3

I don't believe there is any way to pass objects as an input to a component that is routed to. I've accomplished this by using a service with an observable to share the data between a parent and one or many child components.

Basically the parent component calls the service and pushes whatever data it needs to it. In my case it is just an ID, but it could be anything. The Service then can do something with that data (or not). In my example I'm making a call to the server to get a company based on the ID but if you already have the object you need this isn't needed. Then it pushes an object into an Observable stream which is subscribed to in the child component.

Parent Component:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { SalesProcessService } from './salesProcess.service';
import { Subscription } from 'rxjs/Rx';

@Component({
    selector: 'ex-sales-process',
    template: `
        <router-outlet></router-outlet>
    `
})
export class SalesProcessComponent implements OnInit, OnDestroy {
    private companyRowId: string;
    private paramsSubscription: Subscription;
    constructor(
        private salesProcessService: SalesProcessService,
        private route: ActivatedRoute
    ) {}
    ngOnInit() {
        this.paramsSubscription = this.route.params.subscribe((params: Params) => {
            if (this.companyRowId !== params['companyId']) {
                this.companyRowId = params['companyId'];
                this.salesProcessService.getCompany(this.companyRowId);
            }
        });
    }
    ngOnDestroy() {
        this.paramsSubscription.unsubscribe();
    }

}

Service:

import { Injectable } from '@angular/core';
import { CompanyDataService } from '../common/services/data';
import { ReplaySubject } from 'rxjs';
import { Observable, Subject, Subscription } from 'rxjs/Rx';

@Injectable()
export class SalesProcessService {
    private companyLoadedSource = new ReplaySubject<any>(1);
    /* tslint:disable:member-ordering */
    companyLoaded$ = this.companyLoadedSource.asObservable();
    /* tslint:enable:member-ordering */

    constructor (
        private companyDataService: CompanyDataService) { }
    getCompany(companyRowId: string) {
      // Data service that makes http call and returns Observable
        this.companyDataService.getCompany(companyRowId).subscribe(company => this.companyLoadedSource.next(company));
    }

}

Child Component

import { Component, OnInit, OnDestroy } from '@angular/core';
import { SalesProcessService } from '../salesProcess.service';
import { Subscription } from 'rxjs/Rx';

@Component({
    selector: 'ex-company',
    template: require('./company.component.html'),
    styles: [require('./company.component.css')]
})
export class CompanyComponent implements OnInit, OnDestroy {
    company: any;
    private companySub: Subscription;
    constructor(
        private salesProcessService: SalesProcessService
        ) { }
    ngOnInit() {
        this.companySub = this.salesProcessService.companyLoaded$.subscribe(company => {
            this.company = company;
        });
    }
    ngOnDestroy() {
        this.companySub.unsubscribe();
    }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Consider create an Angular2 Service for @Input() or @Output() that is going to get passed more than one layer or to an unrelated component.

Comments

0

You can achieve what you want by:

  • Creating a service that holds some state for you. So the child component can access it later.
  • Passing the data using the router (dynamic route, queryParam, param). Eg: users/:id => users/23
  • Passing the data using a state management library. Eg: Redux

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.