각도 및 디 바운스


160

AngularJS에서는 ng-model 옵션을 사용하여 모델을 디 바운스 할 수 있습니다.

ng-model-options="{ debounce: 1000 }"

Angular에서 모델을 어떻게 디 바운스 할 수 있습니까? 문서에서 디 바운스를 검색하려고했지만 아무것도 찾지 못했습니다.

https://angular.io/search/#stq=debounce&stp=1

해결책은 내 자신의 디 바운스 함수를 작성하는 것입니다.

import {Component, Template, bootstrap} from 'angular2/angular2';

// Annotation section
@Component({
  selector: 'my-app'
})
@Template({
  url: 'app.html'
})
// Component controller
class MyAppComponent {
  constructor() {
    this.firstName = 'Name';
  }

  changed($event, el){
    console.log("changes", this.name, el.value);
    this.name = el.value;
  }

  firstNameChanged($event, first){
    if (this.timeoutId) window.clearTimeout(this.timeoutID);
    this.timeoutID = window.setTimeout(() => {
        this.firstName = first.value;
    }, 250)
  }

}
bootstrap(MyAppComponent);

그리고 내 HTML

<input type=text [value]="firstName" #first (keyup)="firstNameChanged($event, first)">

그러나 함수 빌드를 찾고 있는데 Angular에 있습니까?


3
이것은 github.com/angular/angular/issues/1773 과 관련이있을 수 있지만 아직 명확하지는 않습니다.
Eric Martinez

답변:


202

RC.5 용으로 업데이트

Angular 2를 사용 debounceTime()하면 양식 컨트롤의 valueChanges관찰 가능 항목 에서 RxJS 연산자 를 사용하여 디 바운스 할 수 있습니다 .

import {Component}   from '@angular/core';
import {FormControl} from '@angular/forms';
import {Observable}  from 'rxjs/Observable';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/observable/fromEvent';

@Component({
  selector: 'my-app',
  template: `<input type=text [value]="firstName" [formControl]="firstNameControl">
    <br>{{firstName}}`
})
export class AppComponent {
  firstName        = 'Name';
  firstNameControl = new FormControl();
  formCtrlSub: Subscription;
  resizeSub:   Subscription;
  ngOnInit() {
    // debounce keystroke events
    this.formCtrlSub = this.firstNameControl.valueChanges
      .debounceTime(1000)
      .subscribe(newValue => this.firstName = newValue);
    // throttle resize events
    this.resizeSub = Observable.fromEvent(window, 'resize')
      .throttleTime(200)
      .subscribe(e => {
        console.log('resize event', e);
        this.firstName += '*';  // change something to show it worked
      });
  }
  ngDoCheck() { console.log('change detection'); }
  ngOnDestroy() {
    this.formCtrlSub.unsubscribe();
    this.resizeSub  .unsubscribe();
  }
} 

Plunker

위의 코드에는 아래 주석에서 @albanx의 요청에 따라 창 크기 조정 이벤트를 조절하는 방법에 대한 예제도 포함되어 있습니다.


위의 코드는 아마도 Angular-way 방식이지만 효율적이지 않습니다. 모든 키 입력 및 크기 조정 이벤트는 디 바운스되고 조절 되더라도 변경 감지가 실행됩니다. 다시 말해, 디 바운싱 및 스로틀 링은 변경 감지 실행 빈도에 영향을 미치지 않습니다 . ( Tobias Bosch 의 GitHub 주석 에서이를 확인했습니다.) 플런저를 실행할 때이 내용을 볼 ngDoCheck()수 있으며 입력 상자에 입력하거나 창 크기를 조정할 때 호출 횟수를 확인할 수 있습니다. 크기 조정 이벤트를 보려면 파란색 "x"버튼을 사용하여 플런저를 별도의 창에서 실행하십시오.

보다 효율적인 기술은 Angular의 "영역"외부의 이벤트에서 RxJS Observables를 직접 만드는 것입니다. 이렇게하면 이벤트가 발생할 때마다 변경 감지가 호출되지 않습니다. 그런 다음 구독 콜백 메소드에서 수동으로 변경 감지를 트리거하십시오. 즉, 변경 감지가 호출되는시기를 제어합니다.

import {Component, NgZone, ChangeDetectorRef, ApplicationRef, 
        ViewChild, ElementRef} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/throttleTime';
import 'rxjs/add/observable/fromEvent';

@Component({
  selector: 'my-app',
  template: `<input #input type=text [value]="firstName">
    <br>{{firstName}}`
})
export class AppComponent {
  firstName = 'Name';
  keyupSub:  Subscription;
  resizeSub: Subscription;
  @ViewChild('input') inputElRef: ElementRef;
  constructor(private ngzone: NgZone, private cdref: ChangeDetectorRef,
    private appref: ApplicationRef) {}
  ngAfterViewInit() {
    this.ngzone.runOutsideAngular( () => {
      this.keyupSub = Observable.fromEvent(this.inputElRef.nativeElement, 'keyup')
        .debounceTime(1000)
        .subscribe(keyboardEvent => {
          this.firstName = keyboardEvent.target.value;
          this.cdref.detectChanges();
        });
      this.resizeSub = Observable.fromEvent(window, 'resize')
        .throttleTime(200)
        .subscribe(e => {
          console.log('resize event', e);
          this.firstName += '*';  // change something to show it worked
          this.cdref.detectChanges();
        });
    });
  }
  ngDoCheck() { console.log('cd'); }
  ngOnDestroy() {
    this.keyupSub .unsubscribe();
    this.resizeSub.unsubscribe();
  }
} 

Plunker

나는 그것을 정의 하기 위해 ngAfterViewInit()대신에 사용 합니다 .ngOnInit()inputElRef

detectChanges()이 구성 요소와 해당 하위 요소에서 변경 감지를 실행합니다. 루트 구성 요소에서 변경 감지를 실행하려면 (즉, 전체 변경 감지 확인을 실행) ApplicationRef.tick()대신 사용하십시오. ( ApplicationRef.tick()플 런커의 의견에 전화를 걸었습니다.) 전화 tick()하면 전화 가 걸립니다 ngDoCheck().


2
@Mark Rajcok [value] 대신 입력 값을 업데이트하지 않기 때문에 [value] 대신 [ngModel]을 사용해야한다고 생각합니다.
Milad

1
일반적인 디 바운스 방법이 있습니까 (예 : 창 크기 조정 이벤트에 적용)?
albanx

1
@MarkRajcok 귀하의 답변에 설명 된 CD 문제가 github.com/angular/zone.js/pull/843에
Jefftopia

2
메모리 누수를 방지하려면 언제 구독을 취소해야합니까?
slanden

1
예 @slanden에 acccording netbasal.com/when-to-unsubscribe-in-angular-d61c6b21bad3 , 우리는 구독을 취소한다 .fromEvent()구독
존 Onstott

153

을 다루지 않으려면 변경 바인딩과 함께 @angular/formsRxJS Subject를 사용하면 됩니다.

view.component.html

<input [ngModel]='model' (ngModelChange)='changed($event)' />

view.component.ts

import { Subject } from 'rxjs/Subject';
import { Component }   from '@angular/core';
import 'rxjs/add/operator/debounceTime';

export class ViewComponent {
    model: string;
    modelChanged: Subject<string> = new Subject<string>();

    constructor() {
        this.modelChanged
            .debounceTime(300) // wait 300ms after the last event before emitting last event
            .distinctUntilChanged() // only emit if value is different from previous value
            .subscribe(model => this.model = model);
    }

    changed(text: string) {
        this.modelChanged.next(text);
    }
}

변경 감지를 트리거합니다. 변경 감지를 트리거하지 않는 방법은 Mark의 답변을 확인하십시오.


최신 정보

.pipe(debounceTime(300), distinctUntilChanged()) rxjs 6에 필요합니다.

예:

   constructor() {
        this.modelChanged.pipe(
            debounceTime(300), 
            distinctUntilChanged())
            .subscribe(model => this.model = model);
    }

5
이 솔루션을 선호합니다! angular 2.0.0, rxjs 5.0.0-beta 12로 작업
alsco77

2
완벽하고 간단하며 명확하게 작업했으며 양식이 필요 없습니다. 저는 Angular 4.1.3에 있습니다. rxjs 5.1.1
5

필자는 이것이 필요한 경우 양식으로 작업 할 수있는 옵션이 있기 때문에 탁월한 솔루션이라고 생각하지만 구현을 훨씬 간단하게 만드는 종속성을 제거합니다. 감사.
Max

2
.pipe(debounceTime(300), distinctUntilChanged())rxjs 6에 필요
Icycool

해결책은 저를 구했습니다. 에서의 keyUp이벤트를 사용하고있었습니다. 열 수가 변경 될 때 작동이 중지되었습니다.input.nativeElementmat-table
igorepst

35

지시어로 구현 될 수 있습니다.

import { Directive, Input, Output, EventEmitter, OnInit, OnDestroy } from '@angular/core';
import { NgControl } from '@angular/forms';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import { Subscription } from 'rxjs';

@Directive({
  selector: '[ngModel][onDebounce]',
})
export class DebounceDirective implements OnInit, OnDestroy {
  @Output()
  public onDebounce = new EventEmitter<any>();

  @Input('debounce')
  public debounceTime: number = 300;

  private isFirstChange: boolean = true;
  private subscription: Subscription;

  constructor(public model: NgControl) {
  }

  ngOnInit() {
    this.subscription =
      this.model.valueChanges
        .debounceTime(this.debounceTime)
        .distinctUntilChanged()
        .subscribe(modelValue => {
          if (this.isFirstChange) {
            this.isFirstChange = false;
          } else {
            this.onDebounce.emit(modelValue);
          }
        });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

}

처럼 사용

<input [(ngModel)]="value" (onDebounce)="doSomethingWhenModelIsChanged($event)">

구성 요소 샘플

import { Component } from "@angular/core";

@Component({
  selector: 'app-sample',
  template: `
<input[(ngModel)]="value" (onDebounce)="doSomethingWhenModelIsChanged($event)">
<input[(ngModel)]="value" (onDebounce)="asyncDoSomethingWhenModelIsChanged($event)">
`
})
export class SampleComponent {
  value: string;

  doSomethingWhenModelIsChanged(value: string): void {
    console.log({ value });
  }

  async asyncDoSomethingWhenModelIsChanged(value: string): Promise<void> {
    return new Promise<void>(resolve => {
      setTimeout(() => {
        console.log('async', { value });
        resolve();
      }, 1000);
    });
  }
} 

1
더 많은 수입으로, 나를 위해 일한 : import "rxjs / add / operator / debounceTime"; "rxjs / add / operator / distinctUntilChanged"가져 오기;
Sbl

2
이를 통해 응용 프로그램을 가장 간단하게 구현할 수 있습니다
joshcomley

1
isFirstChange는 초기화에 방출하지 않는 데 사용됩니다
올렉 Polezky에게

2
Angular 8 및 rxjs 6.5.2에서 다음과 같이 변경되었습니다. 당신이 파이프 구문을 사용하려면, 다음을 변경 : import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/distinctUntilChanged';import { debounceTime, distinctUntilChanged } from 'rxjs/operators';this.model.valueChanges .debounceTime(this.debounceTime) .distinctUntilChanged()this.model.valueChanges .pipe( debounceTime(this.debounceTime), distinctUntilChanged() )
kumaheiyama

1
@kumaheiyama가 그의 의견에서 언급 한 변경 사항으로 Angular 9 및 rxjs 6.5.4에서 작동합니다. 지시문을 작성하는 모듈에서 지시문을 내보내는 것을 잊지 마십시오. 또한이 지시문을 작성하는 모듈을 사용중인 모듈에 포함시키는 것을 잊지 마십시오.
Filip Savic

29

화제가 된 때문에, 답변의 대부분은 일을하지 않습니다각도 6/7/8/9 및 / 또는 기타 libs와 사용합니다.
RxJS가 포함 된 Angular 6+를위한 짧고 간단한 솔루션입니다.

필요한 것을 먼저 가져 오십시오.

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

초기화 ngOnInit:

export class MyComponent implements OnInit, OnDestroy {
  public notesText: string;
  private notesModelChanged: Subject<string> = new Subject<string>();
  private notesModelChangeSubscription: Subscription

  constructor() { }

  ngOnInit() {
    this.notesModelChangeSubscription = this.notesModelChanged
      .pipe(
        debounceTime(2000),
        distinctUntilChanged()
      )
      .subscribe(newText => {
        this.notesText = newText;
        console.log(newText);
      });
  }

  ngOnDestroy() {
    this.notesModelChangeSubscription.unsubscribe();
  }
}

이 방법을 사용하십시오 :

<input [ngModel]='notesText' (ngModelChange)='notesModelChanged.next($event)' />

추신 : 더 복잡하고 효율적인 솔루션을 위해 여전히 다른 답변을 확인하고 싶을 수도 있습니다.


1
파기시 구독을 취소하지 않으시겠습니까?
Virendra Singh Rathore

업데이트되었습니다. 알아 주셔서 감사합니다!
Just Shadow

1
@JustShadow 감사합니다! 정말 도움이되었습니다.
Niral Munjariya

이것은 첫 번째 시도에서 완벽하게 작동합니다. 그러나 검색 된 텍스트를 삭제하면 다음 요청이 응답하는 데 너무 오래 걸립니다.
Sadiksha Gautam

이상하다. 여전히 내 측면에서 잘 작동합니다. 더 많은 정보를 공유하거나 새로운 질문을 해 주시겠습니까?
Just Shadow

28

angular1에서와 같이 직접 액세스 할 수 없지만 NgFormControl 및 RxJS 옵저버 블로 쉽게 재생할 수 있습니다.

<input type="text" [ngFormControl]="term"/>

this.items = this.term.valueChanges
  .debounceTime(400)
  .distinctUntilChanged()
  .switchMap(term => this.wikipediaService.search(term));

이 블로그 게시물은이를 명확하게 설명합니다 : http://blog.thoughtram.io/angular/2016/01/06/taking-advantage-of-observables-in-angular2.html

자동 완성을위한 것이지만 모든 시나리오에서 작동합니다.


그러나 서비스에서 오류가 발생했습니다. 다시 실행되지 않습니다
Arun Tyagi

나는 그 예를 이해하지 못한다. [...] 단방향 대상 바인딩입니다. 컨테이너에 통지 할 수있는 이유는 무엇 valueChanges입니까? sth 일 필요는 없습니다. 좋아 (ngFormControl)="..."?
phil294

20

원하는 것을 수행 하는 RxJS (v.6) Observable만들 수 있습니다 .

view.component.html

<input type="text" (input)="onSearchChange($event.target.value)" />

view.component.ts

import { Observable } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';

export class ViewComponent {
    searchChangeObserver;

  onSearchChange(searchValue: string) {

    if (!this.searchChangeObserver) {
      Observable.create(observer => {
        this.searchChangeObserver = observer;
      }).pipe(debounceTime(300)) // wait 300ms after the last event before emitting last event
        .pipe(distinctUntilChanged()) // only emit if value is different from previous value
        .subscribe(console.log);
    }

    this.searchChangeObserver.next(searchValue);
  }  


}

도움 덕분에, 그러나 나는 가져 오기에서해야한다고 생각 rsjs/Rx: 내가 가져 오기에게 당신이 그것을 쓴 방법을 사용하여 오류 ... 그래서 내 경우는 이제했다import { Observable } from 'rxjs/Rx';
ghiscoding

2
@ghiscoding rxjs 버전에 따라 다릅니다. 버전 6에서는 다음과 같습니다 import { Observable } from 'rxjs';..
Matthias

감사! 옆으로, 당신은 하나의 pipe전화를 사용할 수 있습니다pipe(debounceTime(300), distinctUntilChanged())
알.

1
searchChangeObserver는 구독자이므로 searchChangeSubscriber가 더 나은 이름이됩니다.
Khonsort

12

lodash를 사용하는 사람은 모든 기능을 쉽게 디 바운싱 할 수 있습니다.

changed = _.debounce(function() {
    console.log("name changed!");
}, 400);

그런 다음 템플릿에 다음과 같은 것을 던져 넣으십시오.

<(input)="changed($event.target.value)" />

3
또는 그냥 (입력) = "changed ($ event.target.value)"
Jamie Kudla 2016 년

1
lodash로 답변 주셔서 감사합니다 :)
Vamsi

나는 이것이 수신 거부에 관계없이 모든 단일 변경에 대해 각도 변경 감지를 트리거 할 것이라고 생각합니다.
AsGoodAsItGets

5

이벤트 기능에서 직접 초기화 가입자가있는 솔루션 :

import {Subject} from 'rxjs';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';

class MyAppComponent {
    searchTermChanged: Subject<string> = new Subject<string>();

    constructor() {
    }

    onFind(event: any) {
        if (this.searchTermChanged.observers.length === 0) {
            this.searchTermChanged.pipe(debounceTime(1000), distinctUntilChanged())
                .subscribe(term => {
                    // your code here
                    console.log(term);
                });
        }
        this.searchTermChanged.next(event);
    }
}

그리고 html :

<input type="text" (input)="onFind($event.target.value)">

앵귤러 8 기본 자동 완성 텍스트 상자에 완전히 작동합니다. 고마워
Jasmin Akther Suma

4

디 바운스 데코레이터를 작성하여이 문제를 해결했습니다. @debounceAccessor를 속성의 set 접근 자에 적용하면 설명 된 문제를 해결할 수 있습니다.

또한 다른 경우에 유용 할 수있는 방법에 대한 추가 디 바운스 데코레이터를 제공했습니다.

이렇게하면 속성이나 메서드를 매우 쉽게 디 바운싱 할 수 있습니다. 이 매개 변수는 디 바운스가 지속되어야하는 시간 (밀리 초)이며 아래 예에서 100ms입니다.

@debounceAccessor(100)
set myProperty(value) {
  this._myProperty = value;
}


@debounceMethod(100)
myMethod (a, b, c) {
  let d = a + b + c;
  return d;
}

다음은 데코레이터 코드입니다.

function debounceMethod(ms: number, applyAfterDebounceDelay = false) {

  let timeoutId;

  return function (target: Object, propName: string, descriptor: TypedPropertyDescriptor<any>) {
    let originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
      if (timeoutId) return;
      timeoutId = window.setTimeout(() => {
        if (applyAfterDebounceDelay) {
          originalMethod.apply(this, args);
        }
        timeoutId = null;
      }, ms);

      if (!applyAfterDebounceDelay) {
        return originalMethod.apply(this, args);
      }
    }
  }
}

function debounceAccessor (ms: number) {

  let timeoutId;

  return function (target: Object, propName: string, descriptor: TypedPropertyDescriptor<any>) {
    let originalSetter = descriptor.set;
    descriptor.set = function (...args: any[]) {
      if (timeoutId) return;
      timeoutId = window.setTimeout(() => {
        timeoutId = null;
      }, ms);
      return originalSetter.apply(this, args);
    }
  }
}

디 바운스 지연 후 메소드를 트리거 할 수있는 메소드 데코레이터에 대한 추가 매개 변수를 추가했습니다. 예를 들어 마우스 오버 또는 크기 조정 이벤트와 결합 할 때 이벤트 스트림의 끝에서 캡처가 발생하기를 원할 때 사용할 수 있습니다. 그러나이 경우 메서드는 값을 반환하지 않습니다.


3

ngModel의 기본 viewToModelUpdate 함수를 빈 것으로 덮어 쓰는 [debounce] 지시어를 만들 수 있습니다.

지시어 코드

@Directive({ selector: '[debounce]' })
export class MyDebounce implements OnInit {
    @Input() delay: number = 300;

    constructor(private elementRef: ElementRef, private model: NgModel) {
    }

    ngOnInit(): void {
        const eventStream = Observable.fromEvent(this.elementRef.nativeElement, 'keyup')
            .map(() => {
                return this.model.value;
            })
            .debounceTime(this.delay);

        this.model.viewToModelUpdate = () => {};

        eventStream.subscribe(input => {
            this.model.viewModel = input;
            this.model.update.emit(input);
        });
    }
}

사용 방법

<div class="ui input">
  <input debounce [delay]=500 [(ngModel)]="myData" type="text">
</div>

2

HTML 파일 :

<input [ngModel]="filterValue"
       (ngModelChange)="filterValue = $event ; search($event)"
        placeholder="Search..."/>

TS 파일 :

timer = null;
time = 250;
  search(searchStr : string) : void {
    clearTimeout(this.timer);
    this.timer = setTimeout(()=>{
      console.log(searchStr);
    }, time)
  }

2

간단한 해결책은 모든 컨트롤에 적용 할 수있는 지시문을 만드는 것입니다.

import { Directive, ElementRef, Input, Renderer, HostListener, Output, EventEmitter } from '@angular/core';
import { NgControl } from '@angular/forms';

@Directive({
    selector: '[ngModel][debounce]',
})
export class Debounce 
{
    @Output() public onDebounce = new EventEmitter<any>();

    @Input('debounce') public debounceTime: number = 500;

    private modelValue = null;

    constructor(public model: NgControl, el: ElementRef, renderer: Renderer){
    }

    ngOnInit(){
        this.modelValue = this.model.value;

        if (!this.modelValue){
            var firstChangeSubs = this.model.valueChanges.subscribe(v =>{
                this.modelValue = v;
                firstChangeSubs.unsubscribe()
            });
        }

        this.model.valueChanges
            .debounceTime(this.debounceTime)
            .distinctUntilChanged()
            .subscribe(mv => {
                if (this.modelValue != mv){
                    this.modelValue = mv;
                    this.onDebounce.emit(mv);
                }
            });
    }
}

사용법은

<textarea [ngModel]="somevalue"   
          [debounce]="2000"
          (onDebounce)="somevalue = $event"                               
          rows="3">
</textarea>

이 클래스는에서 컴파일되지 않습니다 Angular 7.
Stephane

1

이것에 시간을 보냈 으면 좋겠다. 다른 누군가를 구할 수 있기를 바랍니다. 나에게 debounce컨트롤 에서 사용하는 다음과 같은 접근 방식 이 더 직관적이고 이해하기 쉽습니다. 자동 완성을 위해 angular.io 문서 솔루션을 기반으로하지만 DOM에 데이터를 연결하지 않고도 호출을 가로 챌 수 있습니다.

플 런커

유스 케이스 시나리오는 사용자 이름을 입력 한 후 누군가가 이미 그것을 가지고 있는지 확인한 다음 사용자에게 경고하는 것일 수 있습니다.

참고 : 필요 (blur)="function(something.value)에 따라 더 의미가있을 수 있습니다.


1

RxJS v6을 사용하는 Angular 7의 DebounceTime

소스 링크

데모 링크

여기에 이미지 설명을 입력하십시오

HTML 템플릿에서

<input type="text" #movieSearchInput class="form-control"
            placeholder="Type any movie name" [(ngModel)]="searchTermModel" />

구성 요소

    ....
    ....
    export class AppComponent implements OnInit {

    @ViewChild('movieSearchInput') movieSearchInput: ElementRef;
    apiResponse:any;
    isSearching:boolean;

        constructor(
        private httpClient: HttpClient
        ) {
        this.isSearching = false;
        this.apiResponse = [];
        }

    ngOnInit() {
        fromEvent(this.movieSearchInput.nativeElement, 'keyup').pipe(
        // get value
        map((event: any) => {
            return event.target.value;
        })
        // if character length greater then 2
        ,filter(res => res.length > 2)
        // Time in milliseconds between key events
        ,debounceTime(1000)        
        // If previous query is diffent from current   
        ,distinctUntilChanged()
        // subscription for response
        ).subscribe((text: string) => {
            this.isSearching = true;
            this.searchGetCall(text).subscribe((res)=>{
            console.log('res',res);
            this.isSearching = false;
            this.apiResponse = res;
            },(err)=>{
            this.isSearching = false;
            console.log('error',err);
            });
        });
    }

    searchGetCall(term: string) {
        if (term === '') {
        return of([]);
        }
        return this.httpClient.get('http://www.omdbapi.com/?s=' + term + '&apikey=' + APIKEY,{params: PARAMS.set('search', term)});
    }

    }

1

데코레이터를 사용 하여이 문제를 해결할 수도 있습니다. 예를 들어 utils-decorator lib ( npm install utils-decorators) 의 debounce 데코레이터를 사용하면 다음과 같습니다.

import {debounce} from 'utils-decorators';

class MyAppComponent {

  @debounce(500)
  firstNameChanged($event, first) {
   ...
  }
}

0

이것은 지금까지 내가 찾은 최고의 솔루션입니다. (가) 업데이트 ngModelblurdebounce

import { Directive, Input, Output, EventEmitter,ElementRef } from '@angular/core';
import { NgControl, NgModel } from '@angular/forms';
import 'rxjs/add/operator/debounceTime'; 
import 'rxjs/add/operator/distinctUntilChanged';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/map';

@Directive({
    selector: '[ngModel][debounce]',
})
export class DebounceDirective {
    @Output()
    public onDebounce = new EventEmitter<any>();

    @Input('debounce')
    public debounceTime: number = 500;

    private isFirstChange: boolean = true;

    constructor(private elementRef: ElementRef, private model: NgModel) {
    }

    ngOnInit() {
        const eventStream = Observable.fromEvent(this.elementRef.nativeElement, 'keyup')
            .map(() => {
                return this.model.value;
            })
            .debounceTime(this.debounceTime);

        this.model.viewToModelUpdate = () => {};

        eventStream.subscribe(input => {
            this.model.viewModel = input;
            this.model.update.emit(input);
        });
    }
}

https://stackoverflow.com/a/47823960/3955513 에서 빌린

그런 다음 HTML에서 :

<input [(ngModel)]="hero.name" 
        [debounce]="3000" 
        (blur)="hero.name = $event.target.value"
        (ngModelChange)="onChange()"
        placeholder="name">

blur모델 명시 적으로 일반 자바 스크립트를 사용하여 업데이트됩니다.

예를 들면 다음과 같습니다. https://stackblitz.com/edit/ng2-debounce-working

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.