Angular Form Interview Questions
February 22, 2024
Q.1 : Describe the types of forms created in Angular application.
Ans : There are two types of forms in Angular.1. Reactive Form : Adopts model-driven approach to handle form inputs. Reactive form are useful to create from simple to complex forms. The main classes that handles reactive forms are as below.
FormControl : Creates a form control.
FormGroup : Creates form to group form controls.
FormArray : Creates form controls dynamically.
FormBuilder : Provides methods to shorten creation of FormControl, FormGroup and FormArray.
2. Template-Driven Form : Useful for creating simple forms such as login form, contact form etc. Template-driven forms are created using following directives.
NgModel : Handles value changes in the form element and responds for input validation error.
NgForm : Binds with <form> to track aggregated form value and validation status.
NgModelGroup : Handles validation of sub-group of our form separately from the rest of our form.
Q.2 : How will you create reactive form in Angular?
Ans : ImportReactiveFormsModule
. In TS file, create a FormGroup
instance using FormBuilder.group()
method and group some form controls. Create a function that will be invoked when form is submitted.
userForm = this.formBuilder.group({ name: ['', Validators.required ], pwd: ['', Validators.required ], }); onFormSubmit() { console.log(this.userForm.value); }
FormGroup
instance in <form> element. Bind FormControl
instance using formControlName
directive.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()"> <p>Username : <input formControlName="empId"></p> <p>Password : <input type="password" formControlName="empId"></p> <button>Submit</button> </form>
onFormSubmit()
method will be invoked.
Q.3 : How will you create template-driven form in Angular?
Ans : ImportFormsModule
. In template-driven form, bind ngForm
in <form> element. All the form controls need to use name, ngModel and validation attributes(if any). In TS file, create a method to submit form and assign that method with ngSubmit event.
HTML :
<form #userForm="ngForm" (ngSubmit)="onFormSubmit(userForm)"> <input name="username" ngModel required> <input type="password" name="pwd" ngModel required> <button>Submit</button> </form>
onFormSubmit(form: NgForm) { console.log(form.value); }
Q.4 : Explain FormControl
.
Ans : FormControl
tracks the value and validity status of a form control.
Instantiate
FormControl
in TS file with arguments or without arguments. The arguments we can pass is initial value of form control, disabled true or false, sync and async validators and event to update on.
uname = new FormControl(); address = new FormControl({value: 'Varanasi', disabled: false }, { validators: [Validators.required, Validators.maxLength(100)], asyncValidators: [myAsyncValidator], updateOn: 'change' });
[formControl]
to bind the FormControl
instances.
<input [formControl]="uname"> <input [formControl]="address">
console.log(address.value); console.log(address.status);
Q.5 : Explain FormGroup
.
Ans : FormGroup
tracks the value and validity state of group of FormControl
instances.
Find the TS file.
userForm = new FormGroup({ uname: new FormControl('', [Validators.required]), pwd: new FormControl('', [Validators.required]) }); onFormSubmit() { console.log(this.userForm.value); console.log(this.userForm.status); }
userForm
is FormGroup
instance that need to bind in <form> element. formControlName
will bind FormControl
instances. formControlName
represents single form control of the form.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()"> <p> Username: <input formControlName="name"> </p> <p> Password: <input formControlName="age"> </p> <p> <button type="submit">Submit</button> </p> </form>
Q.6 : Explain FormArray
.
Ans : FormArray
tracks the value and validity state of array of FormControl
, FormGroup
and FormArray
.
Find the code to use
FormArray
within a FormGroup
.
userForm = new FormGroup({ ------ teammates: new FormArray([ new FormControl(), new FormControl() ]) });
teammates
is an instance of FormArray
that is iterated in HTML. formArrayName
binds the FormArray
instance with an HTML element within a <form> element.
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()"> ------ Teammates: <div formArrayName="teammates"> <div *ngFor="let user of teammates.controls; index as i"> <input [formControlName]="i"> </div> </div> <button>SUBMIT</button> </form>
Q.7 : Explain FormBuilder
.
Ans : FormBuilder
provides the following methods.
group() : Constructs a new
FormGroup
.
control() : Constructs a new
FormControl
.
array() : Constructs a new
FormArray
.
record() : Constructs a new
FormRecord
.
Find a sample code to use
FormBuilder
.
constructor(private formBuilder: FormBuilder) this.userForm = this.formBuilder.group({ uname: ['', Validators.required], address: this.formBuilder.group(new Address()), teammates: this.formBuilder.array([]) });
Q.8 : Explain FormRecord
.
Ans : FormRecord
tracks the value and validity state of a collection of FormControl
having same value type. It is same as FormGroup
but FormRecord
can have FormControl
only with same value type. Use FormRecord
to create form dynamically. We can add form controls using addControl
, remove form controls using removeControl
etc.
TS:
@Component({ selector: 'my-app', standalone: true, imports: [CommonModule, ReactiveFormsModule], templateUrl: './my.component.html' }) export class MyComponent implements OnInit { userForm!: FormRecord; formData = [ { title: 'Name', key: 'name' }, { title: 'City', key: 'city' } ]; ngOnInit() { this.userForm = new FormRecord<FormControl<string | null>>({}); this.formData.forEach(data => this.userForm.addControl(data.key, new FormControl()) ); } onFormSubmit() { console.log(this.userForm.value); } }
<form [formGroup]="userForm" (ngSubmit)="onFormSubmit()"> <div *ngFor="let data of formData"> {{data.title}}: <input [formControlName]="data.key"><br /> </div> <button>Submit</button> </form>
Q.9 : How will you use valueChanges
?
Ans : valueChanges
is an observable that emits value of a form control or its group on control value change either by user or programatically. valueChanges
will also emit values if we enable and disable associated form control programatically. valueChanges
can be called on instances of FormControl
, FormGroup
and FormArray
.
Find the sample code.
studentForm = this.formBuilder.group({ stdName: ['', [ Validators.required ]], }); this.studentForm.get('stdName').valueChanges.subscribe( stdName => console.log(stdName); ); this.studentForm.valueChanges.subscribe(student => { console.log(student.stdName); });
Q.10 : How will you use statusChanges
?
Ans : statusChanges
is an observable that emits every time whenever the validation of associated form control is recalculated. statusChanges
can be called on instances of FormControl
, FormGroup
and FormArray
.
studentForm = this.formBuilder.group({ stdName: ['', [ Validators.required ]], }); this.studentForm.get('stdName').statusChanges.subscribe( status => console.log(status); ); this.studentForm.statusChanges.subscribe(status => { console.log(status); });
Q.11 : What is difference between setValue()
and patchValue()
?
Ans : 1. setValue()
and patchValue()
are the methods of FormControl
, FormGroup
and FormArray
.
2.
setValue()
sets the value of control. When we set value for FormGroup
, we need to pass value for all its controls.
3.
patchValue()
patches the value of control. When we patch value for FormGroup
, we can pass value for selected controls.
4. Suppose we have a customer form with three fields name, age and gender.
customerForm = this.formBuilder.group({ name: '' age: '', gender: '' });
setValue()
: Assign values to all the three fields. If we miss any, it will throw error.
this.customerForm.setValue({ name: 'Mahesh' age: 25, gender: 'male' });
patchValue()
: Assign values to only selected fields.
this.customerForm.patchValue({ name: 'Krishna' gender: 'male' });
Q.12 : How will you add and remove controls on FormGroup
dynamically?
Ans : To add control, use addControl()
method with following syntax.
addControl(name: string, control: AbstractControl)
this.customerForm.addControl('city', this.formBuilder.control('', [Validators.required]));
removeControl()
with following syntax.
removeControl(name: string)
this.customerForm.removeControl('city');
Q.13 : How will you replace existing control with new one dynamically in FormGroup
?
Ans : To replace existing control, use setControl()
method with following syntax.
setControl(name: string, control: AbstractControl)
this.customerForm.addControl('city', this.formBuilder.control('', [Validators.maxLength(20)]));
Q.14 : How will you check if a control with the given name exists in FormGroup
?
Ans : FormGroup
has contains()
method that checks if there is any control with the specified name. It has following syntax.
contains(controlName: string): Boolean
const isControlAvailable = this.customerForm.contains('city');
Q.15 : What is difference between (ngModelChange) and (change)?
Ans :ngModelChange
is the @Output
property in NgModel
directive. change
is the DOM event. change
works for HTML input elements on value change and gives that value by $event.target.value
. The ngModelChange
works only with ngModel
and values are obtained directly by $event
.
Q.16 : How will you validate reactive form?
Ans : Create aFormGroup
with FormControl
and FormArray
.
customerForm = this.formBuilder.group({ customerName: ['', [Validators.required, Validators.maxLength(20)]], ------ });
<input formControlName="customerName"> <div *ngIf="customerForm.get('customerName')?.hasError('required')" class="error"> Enter order number. </div> <div *ngIf="customerForm.get('customerName')?.hasError('maxlength')" class="error"> Max length is 20. </div>
Q.17 : How to add async
validation in FormControl
?
Ans : We can pass async validators in following ways.
1. We can pass an array of async validators as third argument of
FormControl
.
customerForm = this.formBuilder.group({ customerName: ['', [Validators.required], [myCustomAsyncValidator()]], });
2. We can pass an object as second argument with properties
validators
and asyncValidators
.
customerForm = this.formBuilder.group({ customerName: ['', { validators: [Validators.required], asyncValidators: [myCustomAsyncValidator()] }], });
Q.18 : How will you validate template-driven form?
Ans : To validate a template-driven from, specify validation attributes to the form control and create a template-reference variable with # using which we can display error messages.<input name="uname" ngModel required maxlength="20" #usrname="ngModel"> <div *ngIf="usrname.errors?.['required']"> Enter user name. </div> <div *ngIf="usrname.errors?.['maxlength']"> Maxlength is 20. </div> {{usrname.status}}
required
and maxlength
. Using usrname display error messages.
Q.19 : How to add validation at runtime in reactive form?
Ans : To add validation, use following methods onFormControl
, FormGroup
and FormArray
.
setValidators : Adds sync validators and override if already exists.
setAsyncValidators : Adds async validators and override if already exists.
addValidators : Adds sync validators and do nothing if already exists.
addAsyncValidators : Adds async validators and do nothing if already exists.
We must call
updateValueAndValidity()
after adding or setting validators to take effect new validations.
get customerName() { return this.customerForm.get('customerName'); } this.customerName.setValidators([Validators.required]); this.customerName.updateValueAndValidity();
Q.20 : How to remove validation at runtime in reactive form?
Ans : To remove validation, use following methods onFormControl
, FormGroup
and FormArray
.
removeValidators() : Removes the specified sync validators.
removeAsyncValidators() : Removes the specified async validators.
clearValidators() : Clears all sync validators.
clearAsyncValidators() : Clears all async validators.
We must call
updateValueAndValidity()
after removing or clearing validators to take effect the changes.
//Instantiate a validator fnMinLength = Validators.minLength(3); //Add the validator this.customerName.addValidators([this.fnMinLength]); this.customerName.updateValueAndValidity(); //Remove the validator this.customerName.removeValidators([this.fnMinLength]); this.customerName.updateValueAndValidity();
Q.21 : What is the role of ngModelGroup
?
Ans : ngModelGroup
is used to group the form controls that are using ngModel
in template-driven form. Using ngModelGroup
we can set and fetch value and validation state of the group. It is same like FormGroup
in reactive form.
Find the sample code to use
ngModelGroup
.
HTML:
<form #customerForm="ngForm" (ngSubmit)="onFormSubmit(customerForm)"> <div ngModelGroup="addressGroup" #addressCtrl="ngModelGroup"> City: <input name="city" ngModel> State: <input name="state" ngModel> Pincode: <input name="pin" ngModel> </div> ------ </form> {{ addressCtrl.status }}
onFormSubmit(form: NgForm) { //Fetch value of the group console.log(form.controls['addressGroup'].value); }
Q.22 : How will you perform required
validation?
Ans : In reactive form, we use Validators.required
in a FormControl
and in template-driven form use required
attribute in a form control.
In reactive form:
customerForm = this.formBuilder.group({ customerName: ['', [Validators.required]] });
<input name="cname" required #customerName="ngModel"> <div *ngIf="customerName.errors?.['required']"> Enter name. </div>
Q.23 : How will you perform minlength
and maxlength
validation?
Ans : In reactive form, we use Validators.minLength
and Validators.maxLength
in a FormControl
and in template-driven form use minlength
and maxlength
attributes in a form control.
In reactive form:
customerForm = this.formBuilder.group({ customerName: ['', [Validators.minLength(3), Validators.maxLength(15)]] });
<input name="cname" minlength="3" maxlength="15" #customerName="ngModel"> <div *ngIf="customerName.errors?.['minlength']"> Min length is 3. </div> <div *ngIf="customerName.errors?.['maxlength']"> Max length is 15. </div>
Q.24 : How will you perform min
and max
validation?
Ans : In reactive form, we use Validators.min
and Validators.max
in a FormControl
and in template-driven form use min
and max
attributes in a form control.
In reactive form:
customerForm = this.formBuilder.group({ customerName: ['', [Validators.min(30), Validators.max(50)]] });
<input name="cname" min="30" max="50" #customerName="ngModel"> <div *ngIf="customerName.errors?.['min']"> Min value is 30. </div> <div *ngIf="customerName.errors?.['max']"> Max value is 50. </div>
Q.25 : How will you perform email
validation?
Ans : In reactive form, we use Validators.email
in a FormControl
and in template-driven form use email
attribute in a form control.
In reactive form:
customerForm = this.formBuilder.group({ customerEmail: ['', [Validators.email]] });
<input name="cemail" email #customerEmail="ngModel"> <div *ngIf="customerEmail.errors?.['email']"> Email not valid. </div>
Q.26 : How will you perform pattern
validation?
Ans : In reactive form, we use Validators.pattern
in a FormControl
and in template-driven form use pattern
attribute in a form control.
In reactive form:
cpattern = "^[a-z0-9_-]{8,20}$"; customerForm = this.formBuilder.group({ userName: ['', [Validators.pattern(this.cpattern)]] });
<input name="uname" pattern="^[a-z0-9_-]{8,20}$" #userName="ngModel"> <div *ngIf="userName.errors?.['pattern']"> Username not valid. </div>
Q.27 : What is property binding?
Ans : In property binding, data is bound from source to view target. Property binding is performed with component property, HTML element and directive. Using component property binding, we can achieve one-way parent-child communication, from parent to child. In HTML element property binding, we can bind component properties to form control properties. It is one-way binding. Use [] to enclose properties to perform property binding.TS
website = {url: "http://www.concretepage.com", title: "CP"}
<a [href]="website.url" [textContent]="website.title"> </a>
Q.28 : What is event binding?
Ans : In event binding, data binding is performed from an element to component. Data obtained from an event such as click and change, can be bound to component properties. Use () to enclose event to perform event binding.TS
<button (click)="sendNotification()">Button</button> <input (change)="onDataChange($event)">
sendNotification() { } onDataChange(inputVal: any) { }
Q.29 : How will you perform two-way binding using ngModel
?
Ans : To perform two-way binding using ngModel
, enclose it with [()] as [(ngModel)]
. It can send data from component to view target as well as from view target to component.
TS
message = "Hellow World!";
<input [(ngModel)]="message"> {{message}}
Q.30 : What is CSS class binding?
Ans : To bind a CSS class, usengClass
with form controls. We can dynamically change the css class using ngClass
directive.
CSS
.myClass { color: green; }
<p [ngClass]="'myClass'"> </p>
Q.31 : How will you mark a form as touched
, dirty
and pristine
programatically?
Ans : Angular provides following methods.
markAsTouched() : marks the control as touched.
markAllAsTouched() : marks all the controls of a
FormGroup
as touched.
markAsUntouched() : Marks a control as untouched.
markAsDirty() : Marks a control as dirty.
markAsPristine() : Marks a control as pristine.
markAsPending() : Marks a control as pending.
Find the sample code snippet.
TS
customerForm = this.formBuilder.group({ cname: ['', [Validators.required]], ------ });
this.customerForm.get('cname')?.markAsDirty(); this.customerForm.markAllAsTouched();