【问题标题】:Remove Output attribute value from Angular component从 Angular 组件中移除 Output 属性值
【发布时间】:2020-07-14 16:54:36
【问题描述】:

我认为实验源于我有时需要为我的 Angular 组件的输出添加和删除函数的情况。 这是例子

父组件将只包含子组件<my-component>的输出函数。

父组件

class ParentComponent{
  myOutputFunction = null;

  setOutputFunction() {
    this.myOutputFunction = () => {
      // do something
    };
  }

  removeOutputFunction() {
    this.myOutputFunction = null;
  }
}

父组件模板

<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 从父级从 () =&gt; // do something 值更改为 null 值。

当我登录 this.someOutput.observers 时,我得到了订阅者数组。 我可以以某种方式使用this.someOutput 作为 EventEmitter 来到达该实验所指向的位置吗?

谢谢

【问题讨论】:

  • 您的问题似乎令人困惑。您能否添加您正在寻找的实际解决方案的简单简短说明。
  • 这里的问题是如果你有(myEvent)="myHandler()",子组件总是会看到一个监听器,即使myHandler 是空的。除了在 null 和函数之间切换底层事件处理程序之外,您是否愿意接受其他方法?
  • @PushprajsinhChudasama 我不知道如何解决这个问题。因为正如 Kurt Hamilton 所说,无论我对 myOutputFunction 做什么,子组件总是有一个监听器。 @KurtHamilton,我愿意接受任何建议,只要我可以在我的子组件中注册我没有订阅者并且只需在子组件的其他逻辑中删除对该事件的订阅
  • @MarioPetrovic 一个问题 - 当父组件摆脱该功能时是否不需要重新渲染子组件?
  • @saglamcem 不,我只需要一个子钩子来响应该函数的父更改,以便我可以做一些更改(不在示例中,但我的情况是我想删除事件侦听器在我的图书馆)

标签: angular typescript rxjs angular-components angular9


【解决方案1】:

你不能动态删除输出属性,但我认为这个解决方案可以帮助你。

如果你想设置从父到子的值,你应该在子组件中使用@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 {}

【讨论】:

  • 感谢您的全面回答。我希望我不必陷入输出/输入解决方案,其中输入被视为改变输出功能。这是因为我不想处理 2 个值(布尔值和函数)。但正如我所见,我的思想实验在 Angular 中是行不通的。绝对输入/输出是使用它的唯一方法,因为我将听取输入更改,然后对子组件中的更改做出反应。在我的情况下,我使用 OpenLayers 组件进行悬停发射,有时我想停止它。非常感谢您的宝贵时间
【解决方案2】:

一旦您使用模板,您就无法通过查看观察者的数量来推断任何东西。即使你这样做了:

<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 本身并让子组件调用它。或者:
  • 一般来说,这听起来像是一个可观察对象的用例:如果(且仅当)有人订阅了它,就应该产生一些东西。消费者是父母,生产者是孩子。接受救援。
  • 这样的模式听起来与组件无关;考虑将 observable/subject 放在服务中。

您可能已经意识到这一切,所以我将其保留在:不,不要将逻辑基于 EventEmitter 的观察者。 *即使你采用程序化方法,你也破坏了一些基本的抽象;正确使用子组件以及子组件的行为需要消费者对子组件逻辑有复杂的了解。

【讨论】:

  • 感谢您的回答。虽然这是一个解决方案,但我认为它太老套了,因为当您开始通过使用ViewChild 访问组件并更改订阅方法来篡改订阅的角度抽象时。此外,使用输入不会给子 -> 父发射。
  • @MarioPetrovic,我将澄清使用 viewchild 不是建议的方法
【解决方案3】:

为什么不使用输入法?

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>

【讨论】:

  • 使用@Input 不会向父组件发出更改。而且在ngOnInit() 中执行此操作只会在子初始化时执行。感谢您的努力,这个答案错过了倾听变化并能够向父母发出变化的意义
【解决方案4】:

这是一个非常有趣的想法。 但只是为了确保您在正确的时间得到它,您应该收听“newListener”事件并在那里执行您的逻辑。检查此链接作为参考https://nodejs.org/api/events.html#events_event_newlistener

....
this.someOutput.once('newListener', (event, listener) => {
    ... // you have a listener
})

...

【讨论】:

  • 我想你错过了这里的技术。这是角度/rxjs。 EventEmitter 这里没有 once 方法。
猜你喜欢
  • 2018-12-16
  • 2016-04-25
  • 1970-01-01
  • 1970-01-01
  • 2019-10-24
  • 1970-01-01
  • 2017-06-26
  • 2016-12-30
相关资源
最近更新 更多