我想到了一个实验,这个实验源于我有时需要为我的Angular组件的Output添加和删除函数的情况。这是的例子
父组件将只包含子组件<my-component>
的输出函数。
ParentComponent
class ParentComponent{
myOutputFunction = null;
setOutputFunction() {
this.myOutputFunction = () => {
// do something
};
}
removeOutputFunction() {
this.myOutputFunction = null;
}
}
ParentComponent模板
<my-component (someOutput)="myOutputFunction($event)"><my-component>
子组件MyComponent
将在内部具有输出someOutput
。这也将成为一个问题,即如何检测父母何时决定进行removeOutputFunction()
,并可能订阅该事件并对其做出反应
MyComponent子组件
class MyComponent {
@Output() someOutput = new EventEmitter();
ngOnInit(): void {
// At this point we can see if there are any observers to someOutput
if(this.someOutput.observers.length > 0) {
console.log('YEY we have a set output method from ParentComponent to MyComponent`s attribute');
} else {
console.log('We have no attribute defined');
}
}
}
在ngOnInit()
中,我们可以检查是否对(someOutput)="myOutputFunction($event)"
进行了编码。
所以,结论。有没有办法监听(订阅(someOutput
从父级() => // do something
值到null
值的变化。
当我记录this.someOutput.observers
时,我得到订阅服务器的数组。我可以用this.someOutput
作为EventEmitter来达到这个实验的目的吗?
感谢
您不能动态删除输出属性,但我认为这个解决方案可以帮助您。
如果要设置从父组件到子组件的值,则应在子组件中使用@Input
。
@Output
用于从子节点向父节点通知某些内容。
解决方案1
如果希望子组件仅在父组件具有函数时发出值,请在有人在侦听时告知子组件。
假设您的发射值为string
类型
子组件
class MyComponent {
@Output() someOutput: EventEmitter<string> = new EventEmitter();
@Input() isParentListening = false;
ngOnInit(): void {
if (this.isParentListening) {
// Parent wants to receive data
this.someOutput.emit("Yay! Parent is listening");
} else {
// Parent is not listening
console.log("My parent doesn't take care of me :(");
}
}
}
父组件
<my-component
[isParentListening]="listenChildComponent"
(someOutput)="myOutputFunction($event)"
></my-component>
class ParentComponent {
listenChildComponent = true;
myOutputFunction = (value: string) => {
// do something
};
}
解决方案2
另一个解决方案是让子组件保持干净,并且不知道这个逻辑,由父组件决定是否必须执行某些操作。
子组件
class MyComponent {
@Output() someOutput: EventEmitter<string> = new EventEmitter();
ngOnInit(): void {
// Output always as if someone were listening
this.someOutput.emit("Yay! Someone is listening (I hope)");
}
}
父组件
当输出事件发生时,父级根本不实现任何逻辑。
<my-component (someOutput)="()=>{}"></my-component>
class ParentComponent {}
一旦使用模板,就无法通过观察者的数量来推断任何内容。即使你做到了:
<my-component (someOutput)="myOutputFunction"><my-component>
在myOutputFunction
为空的情况下,观察者的数量仍然是1。
您可以通过使用ViewChild
有条件地设置观察器的编程方法(而不是建议的方法,请参阅下面的原因*(来部分实现这一点:
@ViewChild(MyComponent, { static: true }) comp: MyComponent;
myOutputFunction = null;
setOutputFunction() {
this.myOutputFunction = () => {
console.log('something');
};
this.comp.someOutput.subscribe(this.myOutputFunction);
}
请参阅演示:https://stackblitz.com/edit/angular-output-programmatic
然而,我认为你做这件事的方式不对。似乎您希望子组件(有条件地(在有人在听的情况下产生一些结果。
- 使用EventEmitter来推断这是错误的;如果您希望子组件中的行为依赖于myOutputFunction,请将@Input((传递给子组件-最简单的方法是,传递
myOutputFunction
本身并让子组件调用它。或者: - 一般来说,这听起来像是一个可观察的用例:如果(并且只有当(有人订阅了它,就应该产生一些东西。消费者是父母,生产者是孩子。以救援为准
- 这样的模式听起来与组件无关;考虑将可观察的/主题放在服务中
你可能已经意识到了这一切,所以我把它留在:不,不要把逻辑建立在EventEmitter的观察者的基础上*即使你采用程序化的方法,你也打破了一些基本的抽象;子组件的正确使用和行为需要消费者对子组件逻辑有复杂的了解。
为什么不使用Input?
class MyComponent {
@Input() func = null;
ngOnInit(): void {
if (func)
func();
else
console.log("I'm child")
}
}
在您的父中
<app-child [func]="functionInParent"></app-child>
functionInParent()
{
console.log("function in parent")
}
//OR
<app-child></app-child>
这是一个非常有趣的想法。但为了确保您得到了正确的时间,您应该收听"newListener"事件并在那里执行逻辑。检查此链接作为参考https://nodejs.org/api/events.html#events_event_newlistener
....
this.someOutput.once('newListener', (event, listener) => {
... // you have a listener
})
...