]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
2678b1a54fade273a9c5865131fbdc9b4a033c19
[ceph-ci.git] /
1 import { Component, ElementRef, EventEmitter, Input, OnInit, Output } from '@angular/core';
2 import { AbstractControl, UntypedFormGroup, FormGroupDirective, NgForm } from '@angular/forms';
3
4 import _ from 'lodash';
5
6 import { Icons } from '~/app/shared/enum/icons.enum';
7
8 /**
9  * This component will render a submit button with the given label.
10  *
11  * The button will disabled itself and show a loading icon when the user clicks
12  * it, usually initiating a request to the server, and it will stay in that
13  * state until the request is finished.
14  *
15  * To indicate that the request failed, returning the button to the enable
16  * state, you need to insert an error in the form with the 'cdSubmitButton' key.
17  * p.e.: this.rbdForm.setErrors({'cdSubmitButton': true});
18  *
19  * It will also check if the form is valid, when clicking the button, and will
20  * focus on the first invalid input.
21  *
22  * @export
23  * @class SubmitButtonComponent
24  * @implements {OnInit}
25  */
26 @Component({
27   selector: 'cd-submit-button',
28   templateUrl: './submit-button.component.html',
29   styleUrls: ['./submit-button.component.scss']
30 })
31 export class SubmitButtonComponent implements OnInit {
32   @Input()
33   form: UntypedFormGroup | NgForm;
34
35   @Input()
36   type = 'submit';
37
38   @Input()
39   disabled = false;
40
41   // A CSS class string to apply to the button's main element.
42   @Input()
43   btnClass: string;
44
45   @Input()
46   ariaLabel: string;
47
48   @Output()
49   submitAction = new EventEmitter();
50
51   loading = false;
52   icons = Icons;
53
54   constructor(private elRef: ElementRef) {}
55
56   ngOnInit() {
57     this.form?.statusChanges.subscribe(() => {
58       if (_.has(this.form.errors, 'cdSubmitButton')) {
59         this.loading = false;
60         _.unset(this.form.errors, 'cdSubmitButton');
61         // Handle Reactive forms.
62         if (this.form instanceof AbstractControl) {
63           (<AbstractControl>this.form).updateValueAndValidity();
64         }
65       }
66     });
67   }
68
69   submit($event: any) {
70     this.focusButton();
71
72     // Special handling for Template driven forms.
73     if (this.form instanceof FormGroupDirective) {
74       (<FormGroupDirective>this.form).onSubmit($event);
75     }
76
77     if (this.form?.invalid) {
78       this.focusInvalid();
79       return;
80     }
81
82     this.loading = true;
83     this.submitAction.emit();
84   }
85
86   focusButton() {
87     this.elRef.nativeElement.offsetParent.querySelector(`button[type="${this.type}"]`).focus();
88   }
89
90   focusInvalid() {
91     const target = this.elRef.nativeElement.offsetParent.querySelector(
92       'input.ng-invalid, select.ng-invalid'
93     );
94
95     if (target) {
96       target.focus();
97     }
98   }
99 }