import { AfterViewInit , ContentChild , Directive , ElementRef , HostBinding , Inject , Input , OnDestroy , Optional , Renderer2 } from '@angular/core' ; import { FormGroupDirective , FormGroupName , NgControl , NgForm , NgModelGroup } from '@angular/forms' ; import { Subject , merge } from 'rxjs' ; import { delay , takeUntil } from 'rxjs/operators' ; import { ObThemeService } from '../theme.service' ; import { ObParentFormDirective } from '../nested-form/parent-form.directive' ; import { WINDOW } from '../utilities' ; deprecated @ Directive ( { selector : '[obFormControlState]' , exportAs : 'obFormControlState' , host : { class : 'ob-form-control-state' } } ) export class ObFormControlStateDirective implements AfterViewInit , OnDestroy { @ Input ( ) pristineValidation = false ; @ Input ( ) mandatory ; @ HostBinding ( 'class.has-error' ) hasErrorClass = false ; @ ContentChild ( NgControl ) ngControl : NgControl ; private readonly form : NgForm | FormGroupDirective ; private readonly group : NgModelGroup | FormGroupName ; private inputContainer ; private inputElement ; private readonly unsubscribe = new Subject ( ) ; constructor ( @ Optional ( ) ngForm , @ Optional ( ) formGroupDirective , @ Optional ( ) formGroupName , @ Optional ( ) modelGroup , @ Optional ( ) private readonly parent , @ Inject ( WINDOW ) private readonly window , theme , private readonly elementRef , private readonly renderer ) { theme . deprecated ( 'form control state' , 'form-field/overview#error-messages' ) ; this . form = ngForm || formGroupDirective ; this . group = modelGroup || formGroupName ; if ( ! this . form ) { throw new Error ( 'You need either a NgForm or a FormGroupDirective for the FormControlStateDirective!' ) ; } } ngAfterViewInit ( ) { if ( ! this . ngControl ) { throw new Error ( 'You need to provide an NgControl for the FormControlStateDirective!' ) ; } this . inputElement = this . elementRef . nativeElement . querySelector ( '[ngModel], [formControlName], [name]' ) ; if ( ! this . inputElement ) { throw new Error ( 'you need to provide either a ngModel or a formControlName for the FormControlStateDirective!' ) ; } this . inputContainer = this . inputElement . parentElement ; merge ( this . form . ngSubmit , this . ngControl . statusChanges ) . pipe ( takeUntil ( this . unsubscribe ) , delay ( 0 ) ) . subscribe ( ( ) => this . generateState ( ) ) ; if ( this . parent ) { this . parent . submit$ . subscribe ( ( ) => this . generateState ( true ) ) ; } this . delayStateGenerationForReactiveForms ( ) ; } ngOnDestroy ( ) { this . unsubscribe . next ( ) ; this . unsubscribe . complete ( ) ; } private delayStateGenerationForReactiveForms ( ) { if ( this . form instanceof FormGroupDirective ) { this . window . setTimeout ( ( ) => this . generateState ( ) , 0 ) ; } } private isMandatory ( ) { return this . mandatory || this . inputElement . hasAttribute ( 'required' ) || this . ngControl . errors ?. required ; } private generateState ( submitted = false ) { this . hasErrorClass = submitted || this . form . submitted || ! this . ngControl . pristine || this . pristineValidation ? this . ngControl . invalid : false ; const mandatory = 'control-mandatory' ; if ( this . isMandatory ( ) && ! this . ngControl . value ) { this . renderer . addClass ( this . inputContainer , mandatory ) ; } else { this . renderer . removeClass ( this . inputContainer , mandatory ) ; } } }