Angular 2+并反跳 [英] Angular 2+ and debounce

查看:57
本文介绍了Angular 2+并反跳的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在AngularJS中,我可以使用ng-model选项来消除模型的反跳.

In AngularJS I was able to debounce a model by using ng-model options.

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

如何在Angular中对模型进行反跳?
我试图在文档中搜索反跳,但找不到任何东西.

How can I debounce a model in Angular?
I tried to search for debounce in the docs but I couldn't find anything.

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

一种解决方案是编写我自己的防抖动功​​能,例如:

A solution would be to write my own debounce function, for example:

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中有一个内置函数吗?

But I'm looking for a built in function, is there one in Angular?

推荐答案

已针对RC.5更新

使用Angular 2,我们可以在表单控件的 valueChanges 上使用RxJS运算符 debounceTime()进行反跳:

With Angular 2 we can debounce using RxJS operator debounceTime() on a form control's valueChanges observable:

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

柱塞

上面的代码还包括一个示例,该示例如何限制窗口大小调整事件,如@albanx在下面的评论中所要求的.

The code above also includes an example of how to throttle window resize events, as asked by @albanx in a comment below.

尽管上面的代码可能是实现它的Angular方法,但效率不高.每次击键和每次调整大小事件(即使它们被去抖和抑制)都将导致更改检测运行.换句话说,去抖动和节流不会影响更改检测运行的频率.(我发现Tobias Bosch的 GitHub评论证实了这一点.)可以在运行插件时看到此消息,并且可以看到在输入框中键入内容或调整窗口大小时调用 ngDoCheck()的次数.(使用蓝色的"x"按钮在单独的窗口中运行导航按钮,以查看调整大小事件.)

Although the above code is probably the Angular-way of doing it, it is not efficient. Every keystroke and every resize event, even though they are debounced and throttled, results in change detection running. In other words, debouncing and throttling do not affect how often change detection runs. (I found a GitHub comment by Tobias Bosch that confirms this.) You can see this when you run the plunker and you see how many times ngDoCheck() is being called when you type into the input box or resize the window. (Use the blue "x" button to run the plunker in a separate window to see the resize events.)

一种更有效的技术是在Angular的区域"之外,根据事件自己创建RxJS Observable.这样,每次事件触发时都不会调用更改检测.然后,在您的订阅回调方法中,手动触发更改检测-也就是说,您可以控制何时调用更改检测:

A more efficient technique is to create RxJS Observables yourself from the events, outside of Angular's "zone". This way, change detection is not called each time an event fires. Then, in your subscribe callback methods, manually trigger change detection – i.e., you control when change detection is called:

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

柱塞

我使用 ngAfterViewInit()而不是 ngOnInit()来确保定义了 inputElRef .

I use ngAfterViewInit() instead of ngOnInit() to ensure that inputElRef is defined.

detectChanges() 将对此组件及其子组件运行更改检测.如果您希望从根组件运行更改检测(即运行完整的更改检测检查),请使用

detectChanges() will run change detection on this component and its children. If you would rather run change detection from the root component (i.e., run a full change detection check) then use ApplicationRef.tick() instead. (I put a call to ApplicationRef.tick() in comments in the plunker.) Note that calling tick() will cause ngDoCheck() to be called.

这篇关于Angular 2+并反跳的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆