简体   繁体   中英

How to pass data from Child to Parent: Angular2

I'm following the docs here: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#child-to-parent

However so far not able to get a string variable from the child into the parent.


The Child

Here I'm sending the category title to the emitter

import { Component,
         ChangeDetectionStrategy,
         EventEmitter,
         Output,
         OnInit,
         ViewEncapsulation } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
    changeDetection: ChangeDetectionStrategy.Default,
    encapsulation: ViewEncapsulation.Emulated,
    selector: 'category',
    styleUrls: [ './category.component.css' ],
    templateUrl: './category.component.html'
})
export class CategoryComponent implements OnInit {
    title: string = '';
    @Output() onCategoryTitled = new EventEmitter<string>();

    constructor(private route: ActivatedRoute) {}

    ngOnInit() {
        this.title = this.route.snapshot.params['title'];
        console.log('this.title', this.title)
        this.onCategoryTitled.emit(this.title);
    }
}

The Parent app.component

Here is the parent, I'm able to see the log from the child, but not the log here

import { Component,
         Directive,
         ElementRef,
         Renderer,
         ChangeDetectionStrategy,
         OnInit,
         ViewEncapsulation } from '@angular/core';

@Component({
    changeDetection: ChangeDetectionStrategy.Default,
    encapsulation: ViewEncapsulation.Emulated,
    selector: 'app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
    catTitle:string;

    onCategoryTitled(cat_title: string) {
        console.log('EVENT recieved cat_title:', cat_title)
        this.catTitle = cat_title;
    }

    ngOnInit() {
        console.log('AppComponent init')
    }
}

Parent markup (Where I need the title)

<div class="container">
    <div class="row"><div class="col-md-12 h20"></div></div>

    <div class="row">
        <div class="col-md-8 col-sm-8">
            <ol class="breadcrumb">
                <li><a href="/wiki">Home</a></li>
                <li>{{ catTitle }}</li>
                <!-- <li><a href="/wiki/category">Categories</a></li> -->
            </ol>
        </div>

        <div class="col-md-2 col-sm-2">
            <div class="input-group">
                <input type="text" class="search-input form-control" placeholder="Search for...">
            </div>
        </div>
    </div>

    <router-outlet></router-outlet>

    <footer class="container col-sm-12">
        <p>©2017 <strong>WikiTags</strong>
    </footer>

</div>

在此处输入图片说明

The method of communication that you're attempting from The Cookbook is to be used when the Child is nested directly in the Parent. In that case, on the Parent you would bind your event handler to the emitted event like in their example:

(onVoted)="onVoted($event)"

Your case is a bit different because you have router-outlet that dynamically loads the component into the parent, and that introduces a bit more complexity. You still need to bind (or subscribe) to the event, but (as you may have encountered) you can't add the binding directly to the router-outlet as that simpler cookbook example shows. You can , however, introduce an "intermediary" service that can communicate the event for you across the router-outlet boundary.

For Example, you could write some sort of "communication" service as follows:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class MyCommunicationService {

    constructor() { }

    private emitChangeSource = new Subject<any>();

    changeEmitted$ = this.emitChangeSource.asObservable();

    // Service message
    emitChange(myMessage: any) {
        this.emitChangeSource.next(myMessage);
    }

}

Emit the event from your child component:

...
export class CategoryComponent implements OnInit {
    constructor(private _myCommunicationService: MyCommunicationService) {}

    doSomething(): void {
        ...
        // Emit your event with message
        this._myCommunicationService.emitChange('some change');
    }
...

Then listen for (subscribe to) the event in the parent component (in your case app.component) that contains the router-outlet :

export class AppComponent implements OnInit {
    constructor(private _myCommunicationService: MyCommunicationService) {

        // Subscribe to the service event
        _myCommunicationService.changeEmitted$.subscribe(myMessage => {
            // TODO: Do what you need to to with the message/value
            ...
        });

    }
}

Let me know if this needs clarification. (I could have also totally missed the boat and assumed that the Child Component is loading within the router-outlet when in reality you're doing something entirely different.)

Note: This is untested code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM