如何观察ng-content中的输入元素变化

Yoh*_*oda 9 angular

如何在子组件观察到输入变化时调用父组件的功能?

以下是HTML结构.

# app.comopnent.html
<form>
  <textbox>
    <input type="text">
  </textbox>
</form>

# textbox.component.html
<div class="textbox-wrapper">
  <ng-content>
</div>
Run Code Online (Sandbox Code Playgroud)

限制如下.

  • TextboxComponent已经ng-content并且需要将input元素投影到它.
  • input元素输入时,在TextboxComponent中发出一个事件.
  • 不想让input元素具有更多属性,例如<input type="text" (input)="event()">.

我正在编写代码,但无法找到解决方案......

# input.directive.ts
@Directive({ selector: 'input', ... })
export class InputDirective {
  ngOnChanges(): void {
    // ngOnChanges() can observe only properties defined from @Input Decorator...
  }
}

# textbox.component.ts
@Component({ selector: 'textbox', ... })
export class TextboxComponent {
  @ContentChildren(InputDirective) inputs: QueryList<InputDirective>;
  ngAfterContentInit(): void {
    this.inputs.changes.subscribe((): void => {
      // QueryList has a changes property, it can observe changes when the component add/remove.
      // But cannot observe input changes...
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

Gün*_*uer 9

input事件正在冒泡,可以在父组件上进行侦听

<div class="textbox-wrapper" (input)="inputChanged($event)">
  <ng-content></ng-content>
</div> 
Run Code Online (Sandbox Code Playgroud)

Plunker的例子


Mar*_*cok 5

ngAfterViewInit(),找到感兴趣的元素,然后命令性地添加事件监听器.下面的代码只假设一个输入:

@Component({
    selector: 'textbox',
    template: `<h3>textbox value: {{inputValue}}</h3>
      <div class="textbox-wrapper">
        <ng-content></ng-content>
      </div>`,
})
export class TextboxComp {
  inputValue:string;
  removeListenerFunc: Function;
  constructor(private _elRef:ElementRef, private _renderer:Renderer) {}
  ngAfterContentInit() {
    let inputElement = this._elRef.nativeElement.querySelector('input');
    this.removeListenerFunc = this._renderer.listen(
      inputElement, 'input', 
      event => this.inputValue = event.target.value)
  }
  ngOnDestroy() {
    this.removeListenerFunc();
  }
}
Run Code Online (Sandbox Code Playgroud)

Plunker

与Günter的声明式方法相比,这个答案本质上是一种必要的方法.如果您有多个输入,这种方法可能更容易扩展.


似乎没有办法使用@ContentChild()(或@ContentChildren())在用户提供的模板中找到DOM元素(即ng-content内容)... @ContentChild(input)似乎不存在的东西.因此我使用的原因querySelector().

在这篇博文中,http://angularjs.blogspot.co.at/2016/04/5-rookie-mistakes-to-avoid-with-angular.html,Kar建议用input选择器定义一个指令(比如InputItem)然后使用@ContentChildren(InputItem) inputs: QueryList<InputItem>;.然后我们不需要使用querySelector().但是,我并不特别喜欢这种方法,因为TextboxComponent的用户必须知道在directives数组中也包含InputItem (我想一些组件文档可以解决问题,但我仍然不是粉丝).这是这种方法的掠夺者.