कोणीय और बहस


160

AngularJS में मैं एनजी-मॉडल विकल्पों का उपयोग करके एक मॉडल की आलोचना कर सकता हूं।

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

मैं एंगुलर में किसी मॉडल की कैसे आलोचना कर सकता हूं? मैंने डॉक्स में बहस की तलाश करने की कोशिश की लेकिन मुझे कुछ नहीं मिला।

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)">

लेकिन मैं फंक्शन में एक बिल्ड की तलाश कर रहा हूं, क्या एंगुलर में कोई है?


3
यह प्रासंगिक github.com/angular/angular/issues/1773 हो सकता है , अभी तक जाहिरा तौर पर प्रत्यारोपित नहीं किया गया है।
एरिक मार्टिनेज

जवाबों:


202

RC.5 के लिए अद्यतन किया गया

कोणीय 2 के साथ हम RxJS ऑपरेटर के debounceTime()नियंत्रण फॉर्म के valueChangesअवलोकन पर उपयोग कर बहस कर सकते हैं :

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 द्वारा पूछा गया है।


यद्यपि उपरोक्त कोड संभवतः ऐसा करने का कोणीय-तरीका है, लेकिन यह कुशल नहीं है। हर कीस्ट्रोके और हर आकार की घटना, भले ही वे विवादित और थ्रॉटल की जाती हैं, परिणाम में परिवर्तन का पता चलता है। दूसरे शब्दों में, डिबगिंग और थ्रॉटलिंग यह प्रभावित नहीं करते हैं कि कितनी बार डिटेक्शन रन बदलते हैं । (मुझे टोबियास बॉश की एक GitHub टिप्पणी मिली जो इसकी पुष्टि करती है।) आप इसे तब देख सकते हैं जब आप प्लंकर चलाते हैं और आप देखते हैं कि ngDoCheck()इनपुट बॉक्स में टाइप करते समय या विंडो का आकार बदलने पर आपको कितनी बार बुलाया जा रहा है। (आकार बदलने की घटनाओं को देखने के लिए एक अलग विंडो में प्लंकर चलाने के लिए नीले "x" बटन का उपयोग करें।)

एक अधिक कुशल तकनीक आरएक्सजेएस ऑब्जर्वबल्स को खुद को घटनाओं से, एंगुलर के "ज़ोन" के बाहर बनाने के लिए है। इस तरह, परिवर्तन का पता लगाने को हर बार ईवेंट आग नहीं कहा जाता है। फिर, अपनी सदस्यता कॉलबैक विधियों में, मैन्युअल रूप से परिवर्तन का पता लगाने को ट्रिगर करें - अर्थात, परिवर्तन का पता लगने पर आप नियंत्रण करते हैं:

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 [मान] के बजाय मुझे लगता है, आपको [ngModel] का उपयोग करना चाहिए, क्योंकि [मूल्य] इनपुट मूल्य को अपडेट नहीं करता है।
मिलाद

1
क्या कोई सामान्य बहस विधि है (उदाहरण के लिए विंडो आकार परिवर्तन पर लागू करने के लिए)?
अल्बानैक्स

1
@MarkRajcok मुझे विश्वास है कि आपने अपने उत्तर में वर्णित सीडी मुद्दे को github.com/angular/zone.js/pull/843
जेफटॉपिया

2
मेमोरी लीक्स को रोकने के लिए हमें सदस्यता समाप्त करने की आवश्यकता कब होगी?
15

1
@slanden हाँ, netbasal.com/when-to-unsubscribe-in-angular-d61c6b21bad3 पर एसीसीडिंग करते हुए , हमें सदस्यता से .fromEvent()सदस्यता समाप्त कर लेनी चाहिए
जॉन ऑनस्टॉट

153

यदि आप सौदा नहीं करना चाहते हैं @angular/forms, तो आप केवल Subjectपरिवर्तन बाइंडिंग के साथ एक RxJS का उपयोग कर सकते हैं ।

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);
    }
}

यह परिवर्तन का पता लगाने को ट्रिगर करता है। उस तरीके के लिए जो परिवर्तन का पता लगाने को ट्रिगर नहीं करता है, मार्क के उत्तर की जांच करें।


अपडेट करें

.pipe(debounceTime(300), distinctUntilChanged()) rxjs 6 के लिए आवश्यक है।

उदाहरण:

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

5
मैं इस समाधान पसंद करते हैं! कोणीय 2.0.0, rxjs 5.0.0-बीटा 12
alsco77

2
पूरी तरह से काम किया, सरल और स्पष्ट, कोई रूप शामिल नहीं। मैं Angular 4.1.3 पर, rxjs 5.1.1
पांचवें

मुझे लगता है कि यह बेहतर समाधान है क्योंकि इसमें जरूरत पड़ने पर रूपों के साथ काम करने का विकल्प होता है, लेकिन उस निर्भरता को लागू करने को हटा देता है जो बहुत सरल है। धन्यवाद।
मैक्स

2
.pipe(debounceTime(300), distinctUntilChanged())rxjs 6 के लिए आवश्यक है
इकाइकोल

समाधान ने मुझे बचा लिया। मैं एक 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
अधिक आयातों के साथ, जो मेरे लिए काम करते हैं: "rxjs / add / operator / debounceTime" आयात करें; आयात "rxjs / add / operator / difUntilChanged";
Sbl

2
अब तक यह सबसे सरल आवेदन विस्तृत लागू करने के लिए बनाता है
joshcomley

1
isFirstChange का उपयोग इनिशियलाइज़ करने के लिए नहीं किया जाता है
ओलेग पोलज़स्की

2
निम्नलिखित परिवर्तनों के साथ कोणीय 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() )
बदलिए

1
Angular 9 और rxjs 6.5.4 में परिवर्तन के साथ काम करता है @kumaheiyama ने अपनी टिप्पणी में कहा है। बस उस मॉड्यूल में निर्देश निर्यात करना न भूलें जहां आप इसे बना रहे हैं। और जिस मॉड्यूल को आप उपयोग कर रहे हैं, उस मॉड्यूल को उस मॉड्यूल में शामिल करना न भूलें, जहाँ आप इसका उपयोग कर रहे हैं।
फ़िलिप सैविक

29

विषय पुराना होने के कारण, अधिकांश उत्तर कोणीय 6/7/8/9 पर काम नहीं करते हैं और / या अन्य परिवादों का उपयोग करते हैं। तो यहाँ RxJS के साथ कोणीय 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
आप इसे नष्ट क्यों नहीं करते?
वीरेंद्र सिंह राठौर

अपडेट किया गया। ध्यान देने के लिए धन्यवाद!
बस शैडो

1
@JustShadow धन्यवाद! यह वास्तव में मददगार था।
निराल मुंजरिया

यह पहली कोशिश में सही काम करता है। लेकिन जब मैं किसी तरह से खोजे गए पाठ को हटाता हूं तो अगला अनुरोध प्रतिक्रिया के लिए बहुत लंबा होता है।
साक्षी गौतम

वह अजीब है। यह अभी भी मेरी तरफ से ठीक काम करता है। क्या आप कृपया अधिक जानकारी साझा कर सकते हैं या इसके लिए कोई नया प्रश्न खोल सकते हैं?
बस शैडो

28

कोणीय 1 की तरह सीधे सुलभ नहीं है लेकिन आप आसानी से 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- नुकसान-of-observables-in-angular2.html

यहाँ यह एक स्वत: पूर्ण के लिए है, लेकिन यह सभी परिदृश्यों पर काम करता है।


लेकिन सेवा से एक त्रुटि है, यह फिर से नहीं चल रहा है
अरुण त्यागी

मैं उदाहरण नहीं समझता। [...] एक तरफ़ा लक्ष्य बंधन है। कंटेनर को अधिसूचित क्यों किया जा सकता है valueChanges? यह sth होना चाहिए नहीं है। पसंद है (ngFormControl)="..."?
22:29 पर phil294

20

आप कर सकते हैं बनाने के एक RxJS (v.6) प्रत्यक्ष करता है कि आप जो चाहते।

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';
मथियास

धन्यवाद! एक तरफ के रूप में, आप बस एक pipeकॉल का उपयोग कर सकते हैंpipe(debounceTime(300), distinctUntilChanged())
अल।

1
searchChangeObserver एक सब्सक्राइबर है, इसलिए searchChangeSubscriber एक बेहतर नाम होगा।
खोंसोर्ट

12

Lodash का उपयोग कर किसी के लिए, यह करने के लिए बहुत आसान है Debounce किसी भी समारोह:

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

तो बस इस तरह से अपने टेम्पलेट में कुछ फेंक:

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

3
या सिर्फ (इनपुट) = "बदला हुआ ($ event.target.value)"
जेमी कुडला

1
:) lodash साथ जवाब देने के लिए धन्यवाद
वामसी

मेरा मानना ​​है कि यह अब भी हर एक बदलाव पर कोणीय परिवर्तन का पता लगाएगा, चाहे वह किसी भी तरह का विवाद हो।
AsGoodAsItGets 15

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 प्राइम एनजी स्वतः पूर्ण पाठ बॉक्स के लिए पूरी तरह से ठीक काम करता है। बहुत बहुत धन्यवाद।
जैस्मीन अक्थर सूमा

4

मैंने डेब्यू डेकोरेटर लिखकर इसे हल किया। वर्णित समस्या को संपत्ति के सेट एक्सेसर पर @debounceAccessor को लागू करके हल किया जा सकता है।

मैंने विधियों के लिए अतिरिक्त डेब्यू डेकोरेटर की भी आपूर्ति की है, जो अन्य अवसरों के लिए उपयोगी हो सकता है।

इससे किसी प्रॉपर्टी या मेथड को डिबेट करना बहुत आसान हो जाता है। पैरामीटर मिलिसेकंड की संख्या है बहस नीचे अंतिम उदाहरण में 100 एमएस होनी चाहिए।

@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

हम एक [डिब्यू] निर्देश बना सकते हैं जो एनकोमॉडल के डिफ़ॉल्ट दृश्य को अधिलेखित करता है। एक खाली एक के साथModelUpdate फ़ंक्शन।

निर्देश कोड

@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
स्टीफन

1

इस पर घंटे बिताए, उम्मीद है कि मैं किसी और को कुछ समय बचा सकता हूं। मेरे लिए debounceएक नियंत्रण पर उपयोग करने के लिए निम्नलिखित दृष्टिकोण अधिक सहज और मेरे लिए समझने में आसान है। यह स्वतः पूर्ण के लिए कोणीय.आईओ डॉक्स समाधान पर बनाया गया है, लेकिन डोम को डेटा बांधने पर निर्भर किए बिना मुझे कॉल को इंटरसेप्ट करने की क्षमता के साथ।

Plunker

यह देखने के लिए टाइप करने के बाद कि कोई व्यक्ति पहले से ही इसे ले चुका है, तो उपयोगकर्ता को चेतावनी देता है, इसके लिए एक उपयोग स्थिति परिदृश्य उपयोगकर्ता नाम की जाँच कर सकता है।

नोट: मत भूलना, (blur)="function(something.value)आप के लिए अपनी आवश्यकताओं के आधार पर अधिक समझदारी हो सकती है।


1

RxJS v6 के साथ कोणीय 7 में डेब्यू टाइम

स्रोत लिंक

डेमो लिंक

यहां छवि विवरण दर्ज करें

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

आप इसे डेकोरेटर का उपयोग करके भी हल कर सकते हैं, उदाहरण के लिए डेब्यूट डेकोरेटर का उपयोग बर्तनों-डेकोरेटर लिब ( npm install utils-decorators) से:

import {debounce} from 'utils-decorators';

class MyAppComponent {

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

0

यह अब तक का सबसे अच्छा समाधान है। अपडेट करता है ngModelपर blurऔरdebounce

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.