Ariel Gueta
Posted on July 8, 2019
In this article, I want to show you how you can use AkitaFormsManager
plugin and achieve the same result (and more) described in this ngrx article.
The Plugin Abilities
Persist Forms - Automatically saves the current control value and update the form value according to the value in the store when the user navigates back to the form.
Provides an API so we can query a form’s values and properties from anywhere. This can be useful for things like multi-step forms, cross-component validation, and more.
Installation
npm i @datorama/akita-ng-forms-manager
Create the Routes
We will have two pages, one is PersonPage
and the second is ConfigPage
:
const routes: Routes = [
{
path: '',
component: PersonComponent,
pathMatch: 'full'
},
{
path: 'config',
component: ConfigComponent
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
The Person Component
Now let's create the PersonComponent
form component:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { AkitaNgFormsManage } from '@datorama/akita-ng-forms-manager';
@Component({
selector: 'person-form',
})
export class HomeComponent implements OnInit, OnDestroy {
person = new FormGroup({
firstName: new FormControl(),
lastName: new FormControl(),
age: new FormControl(21, Validators.required)
});
constructor(private formsManager: AkitaNgFormsManager) {}
ngOnInit() {
this.formsManager.upsert('person', this.person);
}
ngOnDestroy() {
this.formsManager.unsubscribe();
}
}
and the template:
<form [formGroup]="person">
<input formControlName="firstName" placeholder="First Name" />
<input formControlName="lastName" placeholder="Last Name" />
<input
formControlName="age"
placeholder="Age"
type="number"
[ngStyle]="person.invalid && { border: '1px solid red' }"
/>
</form>
My favorite part of this plugin is that we still work with the existing Angular API to create our form.
We created a basic reactive form group which contains the person's details. We are injecting the AkitaNgFormsManager
and calling the upsert
method, giving it the form name and the formGroup
.
From that point on, AkitaNgFormsManager
will track the form value changes and update the store accordingly. It also persists the form state when the user navigates back to the form.
We can also see everything in the dev-tools:
The Config Component
Now, let's create the ConfigComponent
:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { AkitaNgFormsManager } from '@datorama/akita-ng-forms-manager';
@Component({
selector: 'app-config',
templateUrl: './config.component.html',
styleUrls: ['./config.component.css']
})
export class ConfigComponent implements OnInit, OnDestroy {
config = new FormGroup({
minAge: new FormControl(21)
});
constructor(private formsManager: AkitaNgFormsManager) {}
ngOnInit() {
this.formsManager.upsert('config', this.config);
}
ngOnDestroy() {
this.formsManager.unsubscribe();
}
}
Same as before, we create a FormGroup
which contains one FormControl
- the minimum age that the user is required to type at the PersonComponent
form. We also register the form with the AkitaNgFormsManager
so we can query it from any other component in our application.
Cross Component Validation
Now, let's go back to the PersonComponent
and see how we can make the age
control validation dynamic based on the minAge
control value:
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { AkitaNgFormsManager, setValidators } from '@datorama/akita-ng-forms-manager';
export class HomeComponent implements OnInit, OnDestroy {
person = new FormGroup({
firstName: new FormControl(),
lastName: new FormControl(),
age: new FormControl(21, Validators.required)
});
dispose;
constructor(private formsManager: AkitaNgFormsManager) {}
ngOnInit() {
this.formsManager.upsert('person', this.person);
this.dispose = this.formsManager.selectValue<number>('config', 'minAge')
.subscribe(minAge => {
setValidators(this.person.get('age'), [Validators.min(minAge)]);
});
}
ngOnDestroy() {
this.formsManager.unsubscribe();
this.dispose.unsubscribe();
}
}
We can query any form that is registered in AkitaNgFormsManager
. In our case, we use the selectValue
method passing the form name and the form field we need. Note that we also can infer the value using a generic.
Now the only thing that is left is to call the setValidators
method (provides by the plugin) passing the control and a Validators
array.
To preserve existing validators, we can do:
this.dispose = this.formsManager.selectValue<number>('config', 'minAge')
.subscribe(minAge => {
const age = this.person.get('age');
const validators = age.validator;
setValidators(age, [...validators, Validators.min(minAge)]);
});
Read more about the plugin in the docs.
Posted on July 8, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.