UNPKG

first-npm-package-nicule

Version:

This isi first npm package

127 lines (107 loc) 4.54 kB
import {catchError, switchMap, filter, tap, map} from 'rxjs/operators'; import { AfterViewInit, Directive, EventEmitter, Host, Input, OnDestroy, Output } from '@angular/core'; import { FormControl, FormGroup, NgForm } from '@angular/forms'; import { Subscription } from 'rxjs'; import { ActionExecutor, Hypermedia, HypermediaAction } from 'first-npm-package-nicule/core'; export function actionNameFactory(ngForm: NgForm): string { return ngForm.name; } @Directive({ selector: '[hmForm]' }) export class FormDirective implements OnDestroy { private submitSubscription: Subscription; private action: HypermediaAction; @Output() submitSuccess = new EventEmitter(); @Output() submitError = new EventEmitter(); @Output() submitComplete = new EventEmitter(); @Input() set hmForm(action: HypermediaAction | any) { if (action) { this.action = action; this.ngForm.name = action.name; this.subscribeToFormSubmit(); } } @Input() tokenOverride; ngOnDestroy(): void { if (this.submitSubscription) { this.submitSubscription.unsubscribe(); } } constructor(@Host() private ngForm: NgForm, private actionExecutor: ActionExecutor) { } private subscribeToFormSubmit(): void { if (this.submitSubscription) { this.submitSubscription.unsubscribe(); } this.submitSubscription = this.ngForm .ngSubmit.pipe( map(event => event as Event), tap(event => event.preventDefault()), filter(_ => { if (!this.isFormValid()) { this.submitComplete.emit(); } return this.isFormValid(); }), switchMap(event => { return this.tokenOverride ? this.actionExecutor.execute(this.action, this.ngForm.value, true, this.tokenOverride) : this.actionExecutor.execute(this.action, this.ngForm.value); }), catchError((err, caught) => { this.submitError.emit(err); this.submitComplete.emit(); return []; }),) .subscribe({ next: this.onResponse.bind(this) }); } private isFormValid(): boolean { this.validateForm(this.ngForm.control); return this.ngForm.valid || Object.keys(this.ngForm.controls).length === 0; } validateForm(formGroup: FormGroup): void { Object.keys(formGroup.controls) .forEach(field => { const control = formGroup.get(field); if (control instanceof FormControl) { control.markAsTouched({ onlySelf: true }); control.markAsDirty({ onlySelf: true }); } else if (control instanceof FormGroup) { this.validateForm(control); } }); } computeClassifiedErrors(messages: Array<string>): any { return messages.reduce((acc, message) => ({ ...acc, [message.slice(message.lastIndexOf('.') + 1)]: message }), {}); } private onResponse(hypermedia: Hypermedia): void { if (!hypermedia) { this.submitError.emit(); this.submitComplete.emit(); return; } const { class: classes, properties } = hypermedia; if (classes && classes.includes('error')) { if (properties.validationErrors) { const validationErrors = properties.validationErrors; validationErrors.forEach( validationError => this.ngForm .form .controls[validationError.name] .setErrors( this.computeClassifiedErrors(validationError.msg))); this.submitError.emit(validationErrors); } if (properties.msg) { this.submitError.emit(properties.msg); } if (classes.includes('service-unavailable')) { this.submitError.emit({ errorType: 'service-unavailable' }); } } else { this.submitSuccess.emit(hypermedia); } this.submitComplete.emit(); } }