Angular Form Interview Questions

By Arvind Rai, 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 : Import ReactiveFormsModule. 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);
} 
In HTML file, create a form with form controls. Bind 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>  
On click of button, form will be submitted and onFormSubmit() method will be invoked.

Q.3 : How will you create template-driven form in Angular?

Ans : Import FormsModule. 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> 
TS :
onFormSubmit(form: NgForm) {
   console.log(form.value);
} 
On click of submit button, form will be submitted.


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'
}); 
In HTML, use [formControl] to bind the FormControl instances.
<input [formControl]="uname">

<input [formControl]="address"> 
Value and validation can be fetched as below.
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);
   }
} 
HTML:
<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: ''
}); 
Using 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'
}); 
Using 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) 
Add control as below.
this.customerForm.addControl('city', this.formBuilder.control('', [Validators.required])); 
To remove control, use removeControl() with following syntax.
removeControl(name: string) 
Remove ‘city’ control as below.
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) 
Replace control with ‘city’ name.
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 
Suppose we want to check a control with ‘city’ name.
const isControlAvailable = this.customerForm.contains('city'); 
If true, that control is available otherwise not.

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 a FormGroup with FormControl and FormArray.
customerForm = this.formBuilder.group({
    customerName: ['', [Validators.required, Validators.maxLength(20)]],
    ------
}); 
customerName will be validated for required and maxlength validation.
<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()]],
}); 
If we don't have sync validators then pass empty array as second argument.
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}} 
In the above code, there are two validations 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 on FormControl, 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 on FormControl, 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 }} 
TS:
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]]
}); 
In template-driven form:
<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)]]
}); 
In template-driven form:
<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)]]
}); 
In template-driven form:
<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]]
}); 
In template-driven form:
<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)]]
}); 
In template-driven form:
<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"} 
HTML
<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)"> 
HTML
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!"; 
HTML
<input [(ngModel)]="message">

{{message}} 

Q.30 : What is CSS class binding?

Ans : To bind a CSS class, use ngClass with form controls. We can dynamically change the css class using ngClass directive. CSS
.myClass {
    color: green;
} 
HTML
<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]],
     ------
}); 
HTML
this.customerForm.get('cname')?.markAsDirty();
this.customerForm.markAllAsTouched(); 

Reference

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us