Issue
I've seen many ways in jquery and Angular 1 on how to disable a submit button whilst an ajax request is being processed, but not for Angular 2.
So far on the template I have:
<button type="submit" [disabled]="requestSent">Submit</button>
and the following to toggle it's disabled state in the Typescript:
requestSent: boolean = false;
this.httpService.addNewAgent(object)
.subscribe(
data => {
this.requestSent = false;
},
error => {
console.log(error.error);
}
);
But this is rather long winded to do on every single component. Is there a more universal way of dealing with this? Perhaps with interceptors?
Solution
Thanks @DmitriyKhirniy for the reply but I wanted a more universal way of disabling buttons during ajax requests. I found a way using directives, services and the interceptor. So using this you will only ever have to apply the attribute disableDuringAjax
to your button(s).
Template:
<button type="submit" disableDuringAjax>Sign In</button>
If you have a button that also disables due to form validation you could use:
<button type="submit" disableDuringAjax [formValid]="myForm">Sign In</button>
With the [formValid]
simply mentioning the instance of the form in general, the directive will do rest of the work.
Directive (disable-button-during-ajax.directive.ts):
import { Component, OnDestroy, OnInit, Directive, HostListener, HostBinding, ElementRef, Input, OnChanges, SimpleChanges } from '@angular/core';
import { BusyService } from '../../shared/services/busy.service';
import { Subscription, Subject, takeUntil } from 'rxjs';
@Directive({
selector: '[disableDuringAjax]'
})
export class DisableButtonDuringAjax implements OnDestroy, OnInit {
private ngUnsubscribe: Subject<any> = new Subject();
@Input() formValid;
subscription: Subscription;
constructor(private _busyService: BusyService, private el: ElementRef) {
}
checkFormValidation(form)
{
if ((form.valid == true)) {
this.checkAjaxProgress();
}
if ((form.valid == false)) {
this.el.nativeElement.disabled = true;
}
}
checkAjaxProgress()
{
this.subscription = this._busyService.busy$
.pipe(takeUntil(this.ngUnsubscribe)).subscribe(
response => {
if ((response == true)) {
this.el.nativeElement.disabled = true;
}
if ((response == false)) {
this.el.nativeElement.disabled = false;
}
// Check form one more time
if ((this.formValid != null)) {
if ((this.formValid.valid == false)) {
this.el.nativeElement.disabled = true;
}
}
}
);
}
doChecks()
{
// If there is no form to check validation then just check the ajax progress
if ((this.formValid == null)) {
this.checkAjaxProgress();
}
// Else check the forms validation AND ajax progress
else {
this.checkFormValidation(this.formValid);
this.formValid.valueChanges.pipe(takeUntil(this.ngUnsubscribe)).subscribe(data => this.checkFormValidation(this.formValid));
}
}
ngOnInit() {
this.doChecks();
}
ngOnChanges(changes: SimpleChanges)
{
this.doChecks();
}
ngOnDestroy() {
this.ngUnsubscribe.next(null);
this.ngUnsubscribe.complete();
}
}
Service (busy.service.ts):
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class BusyService {
numberOfBusyRequests: number = 0;
numberOfNonBusyRequests: number = 0;
// Observable navItem source
private _busySource = new BehaviorSubject<boolean>(null);
// Observable navItem stream
busy$ = this._busySource.asObservable();
constructor() { }
changeBusy(val) {
if ((val == true)) {
this.numberOfBusyRequests = this.numberOfBusyRequests + 1;
}
else {
this.numberOfNonBusyRequests = this.numberOfNonBusyRequests + 1;
}
if (this.numberOfBusyRequests == this.numberOfNonBusyRequests) {
this._busySource.next(false);
}
else {
this._busySource.next(true);
}
}
}
Interceptor (your own interceptor):
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/do';
import { BusyService } from './busy.service';
@Injectable()
export class ProgressInterceptor implements HttpInterceptor {
constructor(private busyService: BusyService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).do(
event => {
// If request was sent
if ((event.type == 0))
{
this.busyService.changeBusy(true);
}
else
{
this.busyService.changeBusy(false);
}
}
)
}
}
Make sure to include the directive into your app.module or shared module. And also make sure to include the service into your app.module.
UPDATE June 2022 - I've created a library for this now = https://www.npmjs.com/package/ngx-disable-during-ajax
Answered By - Andrew Junior Howard
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.