子组件到父组件通信没有嵌套在角度模板中的子项(Angular 2+)

时间:2017-03-07 16:46:57

标签: angularjs angular

每个回答的帖子,每个教程都会显示EventEmitter()可以用于子组件,如果父母正在侦听,则可以与父组件进行对话;但是,只有在子组件是父模板的一部分时才有效;否则,只能通过应用程序的根组件拾取emit。

这是一个简单的结构(在<ng-content></ng-content>上使用radio-group来转换孩子们):

<radio-group>
  <radio></radio>
  <radio></radio>
  <radio></radio>
</radio-group>

当检查自定义无线电组件时,它应该发出一个事件 - 效果很好。但是自定义无线电组即使正在收听也不会听到这个事件,因为在这个实现中,它的子节点并不属于它的模板。

我不明白Angular Material 2 Radios如何解决这个问题;但对于那些了解Angular 2的人来说,它们是一个很好的参考。

单击Angular's Material 2 Radio Demo的“示例”选项卡以查看我要完成的操作,并单击源按钮以查看我正在尝试复制的相同结构。

同样,我不是要复制并粘贴他们的实现,我试图让子组件在子组件不是父模板的一部分时将事件传递给父组件。

3 个答案:

答案 0 :(得分:1)

当子组件不是父模板的一部分时,它们基本上是内容子组件。它们的范围在父组件中。

例如,如果您有一个名为my-component的组件,并且在其模板中您有类似下面的内容,

<parent [input]='somevar1' (output)='somemethod1()' >
   <child [input]='somevar2' (output)='somemethod2()' ></child>
</parent>

somevar1somevar2somemethod1somemethod2来自my-component的范围。

基于这种理解,可以非常安全地说parentchild可以被视为my-component范围内的兄弟姐妹。因此,您可以使用my-component范围在这两者之间进行通信。

实施例,

@Component({
  selector: 'parent',
  template: `<h1>Parent</h1>
  {{awesomeInput}}
  <hr />
  <ng-content></ng-content>
  `
})
export class ParentComponent { 
   @Input() awesomeInput: string;
}

子组件,

@Component({
  selector: 'child',
  template: `<h1>Child</h1>
  <button (click)='sendAwesomeOutput()'>Click me!!</button>
  `
})
export class ChildComponent {
  @Output() awesomeOutput =  new EventEmitter();

  sendAwesomeOutput(){
    this.awesomeOutput.next('awesome output from child!!');
  }
}

模板中使用上述组件的组件。

@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}</h1>
  <hr />
  <parent [awesomeInput]="defaultInput" >
     <child (awesomeOutput)="getOutputFromChild($event)" ></child>
  </parent>
  `
})
export class AppComponent { 
  name = 'Angular';
  defaultInput = 'default value for parent';

  getOutputFromChild(val){
    this.defaultInput = val;
  }
}

<强>更新

如果您在parent-Child之间传递值,您可能没什么创意,并且可以在模板本身中完全执行。更新了Plunker !!

<parent awesomeInput="{{child1.awesomeOutput | async }}" >
     <child #child1 ></child>
</parent>

如果你必须处理任何事情,上面的那个会考虑场景。

查看此Plunker !!

希望这会有所帮助!!

答案 1 :(得分:1)

如果你转到that plunker,你会发现他们有以下结构:

<radio-ng-model-example>
    <md-radio-group class="example-radio-group" [(ngModel)]="favoriteSeason">
        <md-radio-button class="example-radio-button" *ngFor="let season of seasons" [value]="season">
            {{season}}
        </md-radio-button>
    </md-radio-group>
    <div class="example-selected-value">Your favorite season is: {{favoriteSeason}}</div>
</radio-ng-model-example>

radio-ng-model-example是根组件。因此,他们使用EventEmittermd-radio-buttonmd-radio-group之间进行通信,并使用ngModelmd-radio-groupradio-ng-model-example之间进行通信。

答案 2 :(得分:1)

在不使用ngModel,bindings或EventEmitter的情况下回答标题问题(因为它不能在模板之外工作),并且足够灵活,可以在Angular 2.4中的每个子组件中包含任何类型的内容,这里&# 39;其他实现的另一种方法:

示例:
&#34;演示&#34;在Odin理事会(&#34;组织者&#34;)。只有一位演示者可以一次说话(出现)。接下来的人,向组织者发出他们的意图信号,组织者阻止其他主持人说话,这样新的主持人就可以恢复他们的演示。

(演示截图减去额外的嵌套内容:)
Demo screenshot minus additional nested content 单击任何按钮会导致所有演示者隐藏,但您只需单击该演示者。

<强>用法:

<organizer>
    <presenter>
        <h2>Thor</h2>
        <summary>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Incidunt ea nisi impedit aspernatur sint voluptatum odit aperiam, soluta, explicabo, nesciunt earum quo. Vel quod, ratione ullam deserunt commodi quaerat fugiat!</summary>
        <asgardian-power-point></asgardian-power-point>
    </presenter>
    <presenter>
        <h2>Loki</h2>
        <summary>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Incidunt ea nisi impedit aspernatur sint voluptatum odit aperiam, soluta, explicabo, nesciunt earum quo. Vel quod, ratione ullam deserunt commodi quaerat fugiat!</summary>
        <interjection></interjection>
        <lies></lies>
    </presenter>
    <presenter>
        <h2>Sif</h2>
        <summary>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Incidunt ea nisi impedit aspernatur sint voluptatum odit aperiam, soluta, explicabo, nesciunt earum quo. Vel quod, ratione ullam deserunt commodi quaerat fugiat!</summary>
        <asgardian-power-point></asgardian-power-point>
    </presenter>
</organizer>

<强> organizer.component.html:

<ng-content></ng-content>

<强> organizer.component.ts:

import {
    Component,
    ContentChildren,
    QueryList
} from '@angular/core';

import { PresenterComponent } from '../presenter/presenter.component';

@Component({
    selector: 'organizer',
    templateUrl: './organizer.component.html',
    styleUrls: ['./organizer.component.scss']
})

export class OrganizerComponent {

    @ContentChildren(PresenterComponent) presenters: QueryList<PresenterComponent>;

    stopPresenters() {
        this.presenters.forEach(function(item) {
            item.conclude();
        });
    }

}

<强> presenter.component.html:

<div style="overflow:hidden;" [style.height]="expand ? 'auto' : '30px'">
    <button (click)="present()">Present</button>
    <ng-content></ng-content>
</div>

<强> presenter.component.ts:

import {
    Component,
    Input,
    Inject,
    forwardRef
} from '@angular/core';

import { OrganizerComponent } from '../organizer/organizer.component';

@Component({
    selector: 'presenter',
    templateUrl: './presenter.component.html',
    styleUrls: ['./presenter.component.scss']
})

export class PresenterComponent {

    constructor(@Inject(forwardRef(() => OrganizerComponent)) private organizer:OrganizerComponent) {}

    @Input() expand: boolean = false;

    present() {
        this.organizer.stopPresenters();
        this.expand = true;
    }

    conclude() {
        this.expand = false;
    }

}