,

Real-Time Angular Form Status Updates using Observables

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…

By.

•

min read

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!

 

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

Your email address will not be published. Required fields are marked *