【问题标题】:Angular directive that waits for click Promise to complete等待点击 Promise 完成的 Angular 指令
【发布时间】:2019-07-08 15:09:56
【问题描述】:

更新 1:根据@PierreDuc 的回答,我在这里分叉并创建了一个更简单的版本:Simplified Example。伙计,我记得在 AngularJS 中能够完全劫持(点击)函数并执行它。我明白了,我明白了,不过我喜欢下面的简化提案。那应该对我有用:)

我创建了一个 Angular 按钮指令,它接受一个方法作为 Promise。
单击时,我禁用该按钮。当 Promise 解决后,我会重新启用该按钮。

基本上,在单击时,我想禁用该按钮,直到该按钮事件正在执行的所有处理完成,包括任何 http 调用。

我已经完成了我在这里看到的目标:Stackblitz Example

我不是特别喜欢我的“解决方案”。

这太复杂了。为了让它发挥作用,需要发生三件事。

  1. 指令被添加到按钮。
  2. 设置“waitFor”属性。
  3. “waitFor”函数必须是返回 Promise 的函数。

IMO,需要调整的东西太多了。

我真正想做的是获取按钮的 (click) 方法的句柄,并在指令中手动执行它,就像我执行“waitFor”属性的方式一样。

我该怎么做?

至少,我想要一个不需要指令名称(“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>

谢谢!

【问题讨论】:

    标签: angular es6-promise angular-directive


    【解决方案1】:

    我想您可以将其简化为:

    @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 属性将自动设置,您可以插入一个返回 promise 或 observable 的函数。

    stack;

    【讨论】:

    • 非常感谢您的回复!这确实是一个更简单的用法。我也从你的例子中学到了一些东西,所以 TYVM。我应该对此感到高兴,但是,作为开发人员,我想让它变得更简单,哈哈 :) 工作示例:stackblitz.com/edit/…
    • @user1949561 我已经稍微简化了你的堆栈。链接在答案的底部。我不知道它应该变得更简单:)。您从该指令收到的每个请求都是一行。另外建议,在 99.9& 的情况下,您不应该使用渲染器。它的棱角分明。
    • 爱它,再次非常感谢!啊,'禁用',我喜欢想象我会迭代直到我意识到:P
    猜你喜欢
    • 1970-01-01
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-18
    • 1970-01-01
    • 2011-10-20
    • 2018-07-17
    相关资源
    最近更新 更多