Angular, 用户点击按钮或多次提交如何处理?

Angular , how to handle when user click button or submit multiple times?

如何防止用户多次提交表单?我现在的问题是,当用户多次单击提交按钮时,它会创建多个用户。它应该只创建一次用户并在创建另一个用户之前等待。

这是我的资料:

<button mat-flat-button color="primary" [disabled]="userStatus == 'USER_EXISTS_ON_CURRENT_ACCOUNT'" (click)="createUser()">Create
                        User</button>

打字稿:

createUser() {
    this.accountService.create(this.modelForm.value).pipe(
      finalize(() => {
        this.isInProgress = false;
      })
    ).subscribe({next: (res) => { this.notificationService.showSuccess('User has been created successfully.');
        this._router.navigate(['settings/user']);
      },
      error: (err) => {this.notificationService.showError('Something went wrong, Try again later.');
        this.isInProgress = false;
      },
      complete: () => {
        this.isInProgress = false;
      },
    });
  }

如果您想要的功能是限制用户再次单击按钮,直到 API 响应之前的单击事件的值,您可以执行以下操作,

在您的 component.html 文件中,

<button mat-flat-button color="primary" [disabled]="isButtonDisabled()" (click)="createUser()">Create User </button>

在您的 component.ts 文件中,

  • 创建一个布尔型变量,初始值为false。 disableUserCreation: boolean = false;

  • 创建以下函数,

isButtonDisabled(): boolean {
    if (this.userStatus == 'USER_EXISTS_ON_CURRENT_ACCOUNT' || this.disableUserCreation) {
        return true;
    }
    return false;
}

然后,

createUser() {
    this.disableUserCreation = true;
    this.accountService.create(this.modelForm.value).pipe(
      finalize(() => {
        this.isInProgress = false;
      })
    ).subscribe({next: (res) => { this.notificationService.showSuccess('User has been created successfully.');
        this._router.navigate(['settings/user']);
      },
      error: (err) => {this.notificationService.showError('Something went wrong, Try again later.');
        this.isInProgress = false;
      },
      complete: () => {
        this.isInProgress = false;
        this.disableUserCreation = false;
      },
    });
}

我稍微更新了你的代码,

1 - 我们必须在模板中创建一个用户按钮并且

    <button #createUserBtn mat-flat-button color="primary" [disabled]="userStatus == 'USER_EXISTS_ON_CURRENT_ACCOUNT'"> CreateUser </button>

2 - 访问 .ts 文件中的创建用户按钮

@ViewChild('createUserBtn', {static:true}) button;

3 - 创建变量clicks$来存储点击事件

clicks$: Observable<any>;

4 - 在 ngOnInit 中:初始化 clicks$ 变量以侦听点击事件

this.clicks$ = fromEvent(this.button.nativeElement, 'click');

5 - 在 ngOnInit 中:在每个点击事件中,即从 click$ 开始,我们会将我们的事件传递给 exhaustMap

The beauty of exhaustMap is once the first (outer observable) event is triggered it will stop listening to events(Outer Observable) untill it completes its inner observable

所以在我们的例子中,当用户第一次点击按钮(事件)时,exhaustMap 将停止监听按钮点击事件,直到它完成我们的 API 调用 createUser().这个 API 调用 observable 我们将使用 handleResponse() 方法处理。

ngOnInit() {
    this.clicks$ = fromEvent(this.button.nativeElement, 'click');
    
    const result$ = this.clicks$.pipe(
        tap(x => console.log('clicked.')),
        exhaustMap(ev => {
            console.log(`processing API call`);
            return this.createUser();
        })
    );
    
    result$.subscribe(this.handleResponse());
}

创建用户API调用

createUser(): Observable<any> {
    return this.accountService.create(this.modelForm.value).pipe(
      finalize(() => (this.isInProgress = false))
    );
  }

处理响应

handleResponse(): any {
    return {
      next: res => {
        this.notificationService.showSuccess('User has been created successfully.');
        this._router.navigate(['settings/user']);
      },
      error: err => {
        this.notificationService.showError('Something went wrong, Try again later.');
        this.isInProgress = false;
      }
      complete: () => this.isInProgress = false;
    };
  }

Demo

如果您无法访问按钮,您可以将 ngOnit 代码移动到 AfterViewInit 如果有任何错误请告诉我,因为我还没有完全测试你的代码。

 ngAfterViewInit(): void {
    fromEvent(this.button.nativeElement, 'click')
      .pipe(
        tap(x => console.log('clicked.')),
        exhaustMap(ev => {
          console.log(`processing API call`);
          return this.createUser();
        })
      )
      .pipe(tap(x => console.log('Api call completed....')))
      .subscribe(this.handleResponse());
  }