Angular 等待点击 Promise 完成的指令
Angular directive that waits for click Promise to complete
更新 1: 根据@PierreDuc 的回答,我在这里分叉并创建了一个更简单的版本:Simplified Example。伙计,我记得在 AngularJS 中能够完全劫持 (click) 函数并执行它。我明白了,我明白了,不过我喜欢下面的简化建议。这应该对我有用:)
我创建了一个 Angular 按钮指令,它接受一个方法作为 Promise。
单击时,我禁用该按钮。解决 Promise 后,我会重新启用该按钮。
基本上,在单击时我想禁用该按钮,直到该按钮事件正在执行的所有处理完成,包括任何 http 调用。
我已经完成了我在这里看到的目标:Stackblitz Example。
我不是特别喜欢我的 "solution"。
太复杂了。为了让它发挥作用,需要做三件事。
- 将指令添加到按钮。
- "waitFor" 属性 进行设置。
- "waitFor" 函数必须是 returns Promise 的函数。
IMO,要使它正常工作需要调整的东西太多了。
我真正想做的是获取按钮的 (click) 方法的句柄,并按照我 "waitFor" 属性.[= 的方式在指令中手动执行它16=]
我该怎么做?
至少,我想要一个不需要指令名称 ("appClickWait") 和 属性 ("[waitFor]") 的指令。
为了方便起见,这里是代码:
指令:
import { Directive, HostListener, ElementRef, Output, Input, EventEmitter, Renderer2 } from '@angular/core';
// Enfore this directvie can only be used on a button?
@Directive({
selector: '[appClickWait]'
})
export class ClickWaitDirective {
@Input("waitFor") clickWait: any;
constructor(private el: ElementRef, private renderer: Renderer2) { }
@HostListener('click', ['$event'])
clickEvent(event) {
event.preventDefault();
event.stopPropagation();
this.renderer.setAttribute(this.el.nativeElement, 'disabled', 'disabled');
const originalInnerText = this.el.nativeElement.innerText;
this.el.nativeElement.innerText = 'Processing...';
const reset = () => {
this.renderer.removeAttribute(this.el.nativeElement, 'disabled');
this.el.nativeElement.innerText = originalInnerText;
};
// I really would like to just get a handle on the (click) function here
// that would greatly simplify the useage of this directive
this.clickWait()
.then((data) => {
reset();
})
.catch(err => {
console.error(err);
reset();
});
}
}
模板:
myClickFunc = async () => {
console.log('start')
this.posts = [];
// too fast, let's wait a bit
// this.posts = await this.http.get('https://jsonplaceholder.typicode.com/posts').toPromise();
await new Promise((resolve, reject) => {
setTimeout(async () => {
try {
this.posts = await this.http.get('https://jsonplaceholder.typicode.com/posts').toPromise();
} catch (err) {
reject(err);
}
resolve();
}, 1000);
});
console.log('all done');
}
<button type="button" appClickWait [waitFor]="myClickFunc">Single Wait Click</button>
谢谢!
我想你可以将其简化为:
@Directive({
selector: 'button[appClickWait]'
})
export class ClickWaitDirective {
@HostBinding('disabled')
public waiting = false;
@Input()
appClickWait: () => Observable<any> | Promise<any> = async() => void 0;
@HostListener('click')
clickEvent() {
this.waiting = true;
from(this.appClickWait()).pipe(take(1)).subscribe({
subscribe: () => this.waiting = false,
complete: () => this.waiting = false,
error: (e) => {
console.error(e);
this.waiting = false;
}
})
}
}
这种用法:
<button [appClickWait]="myClickFunc">Single Wait Click</button>
myClickFunc = () => this.callHttp();
这样它只能在一个按钮上工作。 disabled 属性将自动设置,您可以插入一个 returns promise 或 observable 的函数。
更新 1: 根据@PierreDuc 的回答,我在这里分叉并创建了一个更简单的版本:Simplified Example。伙计,我记得在 AngularJS 中能够完全劫持 (click) 函数并执行它。我明白了,我明白了,不过我喜欢下面的简化建议。这应该对我有用:)
我创建了一个 Angular 按钮指令,它接受一个方法作为 Promise。
单击时,我禁用该按钮。解决 Promise 后,我会重新启用该按钮。
基本上,在单击时我想禁用该按钮,直到该按钮事件正在执行的所有处理完成,包括任何 http 调用。
我已经完成了我在这里看到的目标:Stackblitz Example。
我不是特别喜欢我的 "solution"。
太复杂了。为了让它发挥作用,需要做三件事。
- 将指令添加到按钮。
- "waitFor" 属性 进行设置。
- "waitFor" 函数必须是 returns Promise 的函数。
IMO,要使它正常工作需要调整的东西太多了。
我真正想做的是获取按钮的 (click) 方法的句柄,并按照我 "waitFor" 属性.[= 的方式在指令中手动执行它16=]
我该怎么做?
至少,我想要一个不需要指令名称 ("appClickWait") 和 属性 ("[waitFor]") 的指令。
为了方便起见,这里是代码:
指令:
import { Directive, HostListener, ElementRef, Output, Input, EventEmitter, Renderer2 } from '@angular/core';
// Enfore this directvie can only be used on a button?
@Directive({
selector: '[appClickWait]'
})
export class ClickWaitDirective {
@Input("waitFor") clickWait: any;
constructor(private el: ElementRef, private renderer: Renderer2) { }
@HostListener('click', ['$event'])
clickEvent(event) {
event.preventDefault();
event.stopPropagation();
this.renderer.setAttribute(this.el.nativeElement, 'disabled', 'disabled');
const originalInnerText = this.el.nativeElement.innerText;
this.el.nativeElement.innerText = 'Processing...';
const reset = () => {
this.renderer.removeAttribute(this.el.nativeElement, 'disabled');
this.el.nativeElement.innerText = originalInnerText;
};
// I really would like to just get a handle on the (click) function here
// that would greatly simplify the useage of this directive
this.clickWait()
.then((data) => {
reset();
})
.catch(err => {
console.error(err);
reset();
});
}
}
模板:
myClickFunc = async () => {
console.log('start')
this.posts = [];
// too fast, let's wait a bit
// this.posts = await this.http.get('https://jsonplaceholder.typicode.com/posts').toPromise();
await new Promise((resolve, reject) => {
setTimeout(async () => {
try {
this.posts = await this.http.get('https://jsonplaceholder.typicode.com/posts').toPromise();
} catch (err) {
reject(err);
}
resolve();
}, 1000);
});
console.log('all done');
}
<button type="button" appClickWait [waitFor]="myClickFunc">Single Wait Click</button>
谢谢!
我想你可以将其简化为:
@Directive({
selector: 'button[appClickWait]'
})
export class ClickWaitDirective {
@HostBinding('disabled')
public waiting = false;
@Input()
appClickWait: () => Observable<any> | Promise<any> = async() => void 0;
@HostListener('click')
clickEvent() {
this.waiting = true;
from(this.appClickWait()).pipe(take(1)).subscribe({
subscribe: () => this.waiting = false,
complete: () => this.waiting = false,
error: (e) => {
console.error(e);
this.waiting = false;
}
})
}
}
这种用法:
<button [appClickWait]="myClickFunc">Single Wait Click</button>
myClickFunc = () => this.callHttp();
这样它只能在一个按钮上工作。 disabled 属性将自动设置,您可以插入一个 returns promise 或 observable 的函数。