Как я могу отменить @Output внутреннего компонента?

У меня есть компонент, который обертывает другой компонент <inner-component> и привязывается к настраиваемому событию InnerComponent.innerChanged(). Я хочу пузыриться с использованием свойства @output, но также хочу отменить вывод.

Как использовать RxJS .debounce() или .debounceTime() для этого?

Что-то вроде этого:

import {Component, Output, EventEmitter} from 'angular2/core';
import 'rxjs/add/operator/debounce';
import 'rxjs/add/operator/debounceTime';

@Component({
  selector: 'debounced-component',
  template: `
    <div>
      <h1>Debounced Outer Component</h1>
      // export class InnerComponent{
      //   @Output() innerChanged: new EventEmitter<string>();
      //   onKeyUp(value){
      //     this.innerChanged.emit(value);
      //   }
      // }
      <input #inner type="text" (innerChange)="onInnerChange(inner.value)">
    </div>
  `
})
export class DebouncedComponent {
  @Output() outerValueChanged: new EventEmitter<string>();

  constructor() {}

  onInnerChange(value) {
    this.outerValuedChanged.emit(value); // I want to debounce() this.
  }
}

Ответ 1

Чтобы отбросить значения, вы можете использовать тему. Субъект является как наблюдаемым, так и наблюдателем. Это означает, что вы можете рассматривать его как наблюдаемый и передавать ему значения.

Вы можете использовать это, чтобы передать новые значения из внутреннего компонента и отменить его таким образом.

export class DebouncedComponent {
  @Output() outerValueChanged: new EventEmitter<string>();
  const debouncer: Subject<string> = new Subject<string>();

  constructor() {
      // you listen to values here which are debounced
      // on every value, you call the outer component
      debouncer
        .debounceTime(100)
        .subscribe((value) => this.outerValuedChanged.emit(value));
  }

  onInnerChange(value) {
    // send every value from the inner to the subject
    debouncer.next(value);
  }
}

Это непроверенный псевдокод. Вы можете увидеть рабочий пример концепции здесь (http://jsbin.com/bexiqeq/15/edit?js,console). Это без углов, но концепция остается прежней.


Обновление: Для более новых версий Angular вам может потребоваться небольшое изменение: изменение debouncer.debounceTime(100) изменяется на debouncer.pipe(debounceTime(100))

constructor() {
      // you listen to values here which are debounced
     // on every value, you call the outer component
     debouncer
       .pipe(debounceTime(100))
       .subscribe((value) => this.outerValuedChanged.emit(value));
}

Ответ 2

Вот рабочий пример Класс со всеми необходимыми импортами, Angular 4+, TypeScript и tslint-friendly:) думал, что это может помочь некоторым людям искать то, что я искал несколько минут назад!

import { Component, Input, Output, EventEmitter, ViewChild, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/debounceTime';

@Component({
  selector: 'app-searchbox',
  template: `
    <input type="text" autocomplete="off" [(ngModel)]="query" [placeholder]="placeholder" (change)="onInputChange($event)">
  `
})
export class SearchboxComponent implements OnDestroy {
  @Input() debounceTime = 500;
  @Output() change = new EventEmitter<string>();

  query = '';
  placeholder = 'Search...';
  results;

  debouncer = new Subject<string>();
  subs = new Array<Subscription>();

  constructor() {
    this.subs.push(this.debouncer.debounceTime(this.debounceTime).subscribe(
      (value: string) => { this.change.emit(value); },
      (error) => { console.log(error); }
    ));
  }

  onInputChange(event: any) {
    this.debouncer.next(event.target.value);
  }

  ngOnDestroy() {
    for (const sub of this.subs) {
      sub.unsubscribe();
    }
  }
}