如何从父级到子级以角度发出事件?

cod*_*de1 71 typescript angular

我目前正在使用angular2.通常我们使用@Output()addTab = new EventEmitter(); 然后addTab.emit()向父组件发出一个事件.从父母到孩子,我们有什么方法可以做副诽谤.

Blu*_*lue 117

使用RxJs,您可以在父组件中声明Subject并将其作为Observable传递给子组件,子组件只需要订阅此Observable.

家长组件

private eventsSubject: Subject<void> = new Subject<void>();

emitEventToChild() {
  this.eventsSubject.next()
}
Run Code Online (Sandbox Code Playgroud)

家长HTML

<child [events]="eventsSubject.asObservable()"> </child>    
Run Code Online (Sandbox Code Playgroud)

儿童组分

private eventsSubscription: any

@Input() events: Observable<void>;

ngOnInit(){
  this.eventsSubscription = this.events.subscribe(() => doSomething())
}

ngOnDestroy() {
  this.eventsSubscription.unsubscribe()
}
Run Code Online (Sandbox Code Playgroud)

  • 此外,使用此方法可以将数据与事件一起传递.比如,`this.eventsSubject.next({data});`在父级中,然后`this.events.subscribe(({data})=> doSomething(data));`在子级中. (11认同)
  • 将eventsSubject转换为Observable,防止子组件调用next()。 (4认同)
  • 感谢这个解决方案,它可以工作,但我在控制台中收到错误:“ core.js:6185 ERROR TypeError: Cannot read property 'subscribe' of undefined ” 该错误指向 ngOnInit 中的 events.subscribe()子组件的:“ this.eventsSubscription = this.events.subscribe(() =&gt; doSomething());” 我正在使用版本:“@angular/cli”:“~9.1.0”和“rxjs” :“~6.5.4” (3认同)
  • 我已经编辑了这个很棒的答案以添加取消订阅。+1 (2认同)
  • 这里可能是一个初学者问题:为什么将 `eventsSubject` 转换为 Observable 而不是仅仅将其订阅为 Subject? (2认同)

小智 55

据我所知,有两种标准方法可以做到这一点.

1. @Input

只要父项中的数据发生更改,子项就会在ngOnChanges方法中得到通知.孩子可以采取行动.这是与孩子互动的标准方式.

Parent-Component
public inputToChild: Object;

Parent-HTML
<child [data]="inputToChild"> </child>       

Child-Component: @Input() data;

ngOnChanges(changes: { [property: string]: SimpleChange }){
   // Extract changes to the input property by its name
   let change: SimpleChange = changes['data']; 
// Whenever the data in the parent changes, this method gets triggered. You 
can act on the changes here. You will have both the previous value and the 
current value here.
}
Run Code Online (Sandbox Code Playgroud)
  1. 共享服务理念

在共享服务中创建服务并使用observable.孩子订阅它,每当有变化时,孩子都会收到通知.这也是一种流行的方法.如果要发送除传递的数据以外的其他内容作为输入,可以使用此功能.

SharedService
subject: Subject<Object>;

Parent-Component
constructor(sharedService: SharedService)
this.sharedService.subject.next(data);

Child-Component
constructor(sharedService: SharedService)
this.sharedService.subject.subscribe((data)=>{

// Whenever the parent emits using the next method, you can receive the data 
in here and act on it.})
Run Code Online (Sandbox Code Playgroud)

  • 鉴于您的意思是 ExpressionChangedAfterItHasBeenCheckedError,在生产模式下不会抛出此错误。 (2认同)

Har*_*tel 9

在父组件中,您可以使用@ViewChild()访问子组件的方法/变量。

@Component({
  selector: 'app-number-parent',
  templateUrl: './number-parent.component.html'
})
export class NumberParentComponent {
    @ViewChild(NumberComponent)
    private numberComponent: NumberComponent;
    increase() {
       this.numberComponent.increaseByOne();
    }
    decrease() {
       this.numberComponent.decreaseByOne();
    }
} 
Run Code Online (Sandbox Code Playgroud)

  • 这似乎比使用 observable 更干净。缺点是必须考虑到孩子。例如,如果孩子加载了路由,这将失败,因为 `numberComponent` 将是 `undefined`。 (6认同)
  • 这是一个好的做法吗?我同意这比可观察量更干净的事实,但我怀疑是否可以从父母那里操纵孩子的变量。不管怎样,它非常适合我的需求,谢谢! (4认同)
  • 这是一个很好的提示。看起来 @ViewChild 在 Angular 8 中发生了变化,或者至少我必须指定 ViewChild 的选项。我在我的例子中使用了这个: @ViewChild(Other, { static: false }) private otherComponent: Other; (2认同)

Nok*_*oki 8

使用子组件中的@Input()装饰器允许父级绑定到此输入.

在子组件中,您按原样声明它:

@Input() myInputName: myType

要将属性从父级绑定到子级,必须在模板中添加绑定括号和它们之间的输入名称.

示例:

<my-child-component [myChildInputName]="myParentVar"></my-child-component>

但要注意,对象作为引用传递,因此如果在子对象中更新对象,则父对象的var将会更新.这可能会导致某些不需要的行为.对于主要类型,将复制该值.

进一步阅读:

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