在AngularJS中,我可以使用ng-model选项来撤销一个模型。
ng-model-options="{ debounce: 1000 }"
如何在Angular中释放一个模型?
我试着在文档里搜索debounce,但什么都没找到。
https://angular.io/search/#stq=debounce&stp=1
一个解决方案是编写我自己的debounce函数,例如:
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中有吗?
它可以作为指令来执行
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);
});
}
}
我通过编写一个debounce decorator来解决这个问题。所描述的问题可以通过将@debounceAccessor应用于属性的集访问器来解决。
我还为方法提供了一个额外的debounce装饰器,它可以在其他场合使用。
这使得撤消属性或方法变得非常容易。该参数是反弹应该持续的毫秒数,在下面的示例中为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);
}
}
}
我为方法装饰器添加了一个额外的参数,让你在debounce延迟后触发方法。我这样做是为了在与鼠标悬停或调整事件相结合时使用它,我希望捕获发生在事件流的末尾。但是,在这种情况下,该方法不会返回值。
这是我迄今为止找到的最好的解决办法。更新ngModelon的模糊和反弹
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">
在模糊模型是显式更新使用纯javascript。
例如:https://stackblitz.com/edit/ng2-debounce-working
它可以作为指令来执行
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);
});
}
}