How can I make an input observable?

2020-06-07 04:24发布

I have a component with a few inputs that I'd like to be notified when it changes. I currently have it working by implementing ngOnChanges and figuring out which input was changed. However, I would prefer set my input declaration to @Input('select-values') selectValues:Observable<any>. This would allow me to subscribe to any new changes that occur in a much cleaner fashion.

ngOnInit() {
    this.selectValues.subscribe(() => console.log('yay!'));
}

Issue with this is that I'm getting exception TypeError: this.selectValues.subscribe is not a function.

Just found out that this also works – Component Interaction. Intercept input property changes with a setter.

标签: angular
3条回答
一纸荒年 Trace。
2楼-- · 2020-06-07 04:52

In fact, it's not possible to directly register against observables associated with events for DOM elements. You need to reference a DOM element directly and use then the fromEvent method of Observable.

Here is a sample:

@Component({
  (...)
  template: `
    <input #input />
  `
})
export class SomeComponent {
  @ViewChild('input')
  input:ElementRef;

  ngAfterViewInit() {
    var eventObservable = Observable.fromEvent(
              this.input.nativeElement, 'keyup');
  }
}

This issue could interest you as well:

That said you can leverage form controls to be notified when input value is updated. The valueChanges attribute of the control could be passed as input of the sub component.

@Component({
  (...)
  template: `
    <input [ngFormControl]='ctrl'/>
    <child-component [select-values]="ctrl.valueChanges"></child-component>
  `
})
export class SomeComponent {
  constructor() {
    this.ctrl = new Control();

    this.ctrl.valueChanges.subscribe(...);
  }
}
查看更多
狗以群分
3楼-- · 2020-06-07 04:54

You can wrap them in a form and listen to changes

this.myForm = fb.group({  
  'sku':  ['', Validators.required]  
});

this.sku = this.myForm.controls['sku'];

this.sku.valueChanges.subscribe(  
  (value: string) => {  
    console.log('sku changed to: ', value);  
  }
);

this.myForm.valueChanges.subscribe(  
  (value: string) => {  
    console.log('form changed to: ', value);  
  }
);

http://blog.ng-book.com/the-ultimate-guide-to-forms-in-angular-2/

or

@Component({
   ...,
   template: '<input (change)="onChange($event.target.value)">'
})
class MyComponent {
  this.inputChange =new Subject();

  onChange(e) {
    this.inputChange.next(e);
  }
}

See also this issue open https://github.com/angular/angular/issues/4062

查看更多
Melony?
4楼-- · 2020-06-07 05:10

If you just need to observe a single input, you can quickly do:

in component:

ngOnInit() {
  this.searchField = new FormControl();
  this.searchField.valueChanges.subscribe(term => {
    console.log('searching for', term);
  });
}

in html:

<input type="search" [formControl]="searchField">

and maybe unsubscribe in ngOnDestroy.

查看更多
登录 后发表回答