We are going to discuss How to check if Angular Form is VALID or INVALID across components. We will be getting real-time updates by deploying RxJS Observables to an Angular form to emit its validity.
While implementing Template-driven or Reactive forms, we may need to get the Form status to emit across components or various modules, or sometimes from child to parent component.
To achieve this we can subscribe to two Observable methods available with form object. We’ll be discussing the implementation with examples for both and the differences between them.
By exposing the form Observable we can accomplish the following scenarios or use cases:
- Emit Form validation status to the Parent component.
- Check the validation status of the Angular form in Parent/ Child or non-relational components.
- Enable/ Disable the page elements based on form valid status.
Let’s get started!
[lwptoc]
Step 1 – Create an Angular Application
Run the following npm commands to create the Angular application.
ng new angular-forms-app
# ? Would you like to add Angular routing? Yes
# ? Which stylesheet format would you like to use? SCSS
Enter the project directory
cd angular-forms-app
Run the application
ng serve --open
Step 2 – Create Parent and Child Component
To easily demonstrate the use cases, we’ll create two new components by hitting the following npm command inside our project root:
ng generate component parent
ng generate component child
The above command will create the ParentComponent and ChildComponent as shown below:
Step 3 – Update Style
To differentiate the components in the application, add the following SCSS style inside the styles.scss file
app-root {
border: 4px solid blue;
display: block;
margin: 10px;
padding: 10px;
}
app-parent {
border: 4px solid red;
display: block;
margin: 10px;
padding: 10px;
}
app-child {
border: 4px solid green;
display: block;
margin: 10px;
padding: 10px;
}
Step 4 – Add components to show-up
After that, open the app.component.html file, then place Parent and Child component tags in it:
<div>
<app-parent></app-parent>
<app-child></app-child>
</div>
Now, when you run the application, it will look like this:
Step 5 – Add Form in Child Component
Now, we’ll add a simple Template Driven Angular form in the ChildComponent
to get its Validation status inside the ParentComponent.
Open the child.component.html file then update it with the following code:
<h3>Child Form</h3>
<form #myForm="ngForm" (ngSubmit)="submitForm($event)">
<input type="text" [(ngModel)]="username" required name="username">
<button>Submit</button>
</form>
We have a super simple form with text input that is required and a button.
Next, open the child.component.ts file to update the Class component as shown below:
// child.component.ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
@ViewChild('myForm', { static: false }) public MyForm: NgForm;
username: string;
constructor() { }
ngOnInit(): void {}
ngAfterViewInit(): void {
this.MyForm.statusChanges.subscribe(res => {
console.log('statusChanges', { res }); // Return VALID or INVALID
})
this.MyForm.valueChanges.subscribe(res => {
console.log('valueChanges', { res }); // Return values of the form
})
}
submitForm(e) {
console.log(this.MyForm.valid);
}
}
Note: Make sure to add the FormsModule
in app.module.ts file to use forms in the Angular application.
In the component class, we have used @ViewChild
decorator to get the form instance we have in the HTML template. The most important thing to notice here is, we are exposing two forms of Observable methods statusChanges
and valueChanges
The subscription to the statusChanges
method will return the status of the form by emitting the VALID or INVALID text whenever a form control value changes.
The valuesChanges
also triggers whenever the value of form is changed, but instead of providing the status, we get the values object of all form controls.
One more thing to notice is, we have these subscriptions inside the ngAfterViewInit
hook of the component which is called after ngAfterContentInit when the component’s view has been initialized.
Step 6 – Emit Child Form Status to Parent
To pass the form status from the Child to the Parent component, we can simply use @Input
and @Output
decorators to emit the current form status value.
Update the app.component.html file, to add a property binding and output function binding as shown below:
<app-parent [FormStatus]="formStatus"></app-parent>
<app-child (getFormStatus)="onGetFormStatus($event)"></app-child>
In the app.component.ts file, we’ll add the definition of onGetFormStatus
method to pass it to the Parent component as input property:
export class AppComponent {
formStatus: string;
constructor() { }
ngOnInit() { }
onGetFormStatus(status: string) {
this.formStatus = status;
}
}
Step 7 – Update Child Component
In the ChildComponent
we’ll emit the form status as an Output event. Open the child.compoennt.ts file and update as shown below:
// child.component.ts
import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
@ViewChild('myForm', { static: false }) public MyForm: NgForm;
username: string;
@Output() getFormStatus = new EventEmitter();
constructor() { }
ngOnInit(): void { }
ngAfterViewInit(): void {
this.MyForm.statusChanges.subscribe(res => {
this.getFormStatus.emit(res); // Emit form status VALID or INVALID
})
this.MyForm.valueChanges.subscribe(res => {
console.log('valueChanges', { res }); // Return values of the form
})
}
submitForm(e) {
console.log(this.MyForm.valid);
}
}
Inside the statusChanges
subscription, we’re directly emitting the changed value.
Step 8 – Update Parent Component
Inside the ParentComponent
, we just need to catch the emitted values from the App component method and get it as input property inside the FormStatus
variable.
export class ParentComponent implements OnInit {
@Input() FormStatus: string;
constructor() { }
ngOnInit(): void {
}
}
And in the Parent template show the status
<h3>Child Form Status: {{FormStatus}}</h3>
That’s it
Now run the application to show the live form status from the Child form in the Parent component.
Conclusion
We’ve discussed how to use Form object to use the statusChanges
and valueChanges
Observable methods to pass the form status from one component to another. We can easily subscribe to these exposed methods in Template as well as Reactive Angular forms.
If we have a non-relational component, then we can easily create a service with Behaviour Subject and get form status to any one or more components. We’ll discuss the service approach in the next article.
Leave a Reply