7
votes

I have a reactive form, where each control follows this basic structure:

<div class="form-group">
    <label for="vtype">Vehicle Type</label>
    <input formControlName="vtype" class="form-control" placeholder="Type"/>
</div>

Angular automatically adds validation classes to each FormControl and FormGroup, such as ng-valid, ng-touched, ng-dirty, etc.

For styling purposes, I would also like to apply these same classes to the control's parent div element. For example:

<div class="form-group ng-dirty ng-touched ng-invalid">
    <label for="vtype">Vehicle Type</label>
    <input formControlName="vtype" class="form-control ng-dirty ng-touched ng-invalid" placeholder="Type"/>
</div>

I have not found a native way to do this with Angular. I attempted to create a directive that would sync the parent div's classes with the control's validation classes, but I am unable to handle the touched event in order to set the ng-touched/ng-untouched classes on the parent element.

Any help would be greatly appreciated!

2
touched flag is set as a response for a simple blur event. You can reproduce it this way.mat3e

2 Answers

2
votes
<div class="form-group ng-dirty ng-touched ng-invalid" [class.ng-invalid]="myForm.vtype.invalid">
    <label for="vtype">Vehicle Type</label>
    <input formControlName="vtype" class="form-control ng-dirty ng-touched ng-invalid" placeholder="Type"/>
</div>

This help you to apply dynamic classes.

0
votes

I see this is an old question, but the answer can be useful.

Create custom directive and use HostBinding:

import { ContentChild, Directive, ElementRef, HostBinding } from '@angular/core';
import { FormControlName } from '@angular/forms';

@Directive({
    selector: 'div.form-group'
})
export class ParentElementValidatorDirective {
    @ContentChild(FormControlName) controlName: FormControlName;
    @HostBinding('class.ng-invalid') get invalid() { return this.controlName.invalid && this.controlName.touched; }
    @HostBinding('class.ng-valid') get valid() { return this.controlName.valid && this.controlName.touched; }
    constructor(element: ElementRef) { }
}

Note the selector of the directive!