Easily synchronize any reactive form to the @ngrx/store
in a few steps.
- ✓ Reactive Forms only
- ✓ Persisting State (additional library)
@larscom/ngrx-store-formsync
depends on @ngrx/store and Angular 12+.
npm i --save @larscom/ngrx-store-formsync
- Import
StoreFormSyncModule.forRoot()
once inside a root module. For every other module, useStoreFormSyncModule.forFeature()
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StoreModule } from '@ngrx/store';
import { StoreFormSyncModule } from '@larscom/ngrx-store-formsync';
@NgModule({
imports: [
BrowserModule,
StoreModule.forRoot(),
// import StoreFormSyncModule.forRoot() only once
StoreFormSyncModule.forRoot()
]
})
export class AppModule {}
- Add the
storeFormSync
directive on the same element asformGroup
and provide astoreFormSyncId
<form [formGroup]="myFormGroup" storeFormSync storeFormSyncId="1">
<div>
<input formControlName="firstName" />
<input formControlName="lastName" />
</div>
<button type="submit">Submit</button>
</form>
Your formGroup will now get synced to the @ngrx/store
export interface StoreFormSyncConfig {
/**
* Only sync to the store when submitting the form.
* @default false
*/
syncOnSubmit: boolean;
/**
* Only sync to the store when the form status is valid.
* @default false
*/
syncValidOnly: boolean;
/**
* Sync the raw form value to the store (this will include disabled form controls)
* @default false
*/
syncRawValue: boolean;
/**
* Serialize function that gets called before dispatch
*/
serialize: (formValue: any) => string;
/**
* Deserialize function that gets called before patching the form.
*
* ISO Date objects which are stored as a string gets revived as Date object by default.
*/
deserialize: (formValue: string) => any;
}
Attribute | Type | Default | Required | Description |
---|---|---|---|---|
formGroup |
FormGroup | undefined | yes | The form group which needs to get synced to the @ngrx/store. |
storeFormSyncId |
string | undefined | yes | The unique ID for the form group. |
storeFormSyncDisabled |
boolean | false | no | Whether the form group value should sync to the @ngrx/store. |
import { Component } from '@angular/core';
import { storeFormSyncSelectors } from '@larscom/ngrx-store-formsync'; // import selectors
import { Store, select } from '@ngrx/store';
@Component({
selector: 'app-my-component',
template: `
<div>
<h1>My Form Value</h1>
{{ myFormValue$ | async | json }}
</div>
`,
styleUrls: ['my-component.component.scss']
})
export class MyComponent {
myFormValue$ = this.store.pipe(select(storeFormSyncSelectors.selectFormValue({ storeFormSyncId: 'myId' })));
constructor(private readonly store: Store) {}
}
import { Component } from '@angular/core';
import { storeFormSyncActions } from '@larscom/ngrx-store-formsync'; // import actions
import { Store, select } from '@ngrx/store';
@Component({
selector: 'app-my-component',
templateUrl: 'my-component.component.html'
styleUrls: ['my-component.component.scss']
})
export class MyComponent {
constructor(private readonly store: Store) {}
setForm(): void {
const value = {
firstName: 'Jan',
lastName: 'Jansen'
};
this.store.dispatch(storeFormSyncActions.setForm({ storeFormSyncId: 'myId', value }));
}
}
import { Component } from '@angular/core';
import { storeFormSyncActions } from '@larscom/ngrx-store-formsync'; // import actions
import { Store, select } from '@ngrx/store';
@Component({
selector: 'app-my-component',
templateUrl: 'my-component.component.html'
styleUrls: ['my-component.component.scss']
})
export class MyComponent {
constructor(private readonly store: Store) {}
patchForm(): void {
const value = {
firstName: 'Jan' // lastName can be omitted
//lastName: 'Jansen'
};
this.store.dispatch(storeFormSyncActions.patchForm({ storeFormSyncId: 'myId', value }));
}
}
import { Component } from '@angular/core';
import { storeFormSyncActions } from '@larscom/ngrx-store-formsync'; // import actions
import { Store, select } from '@ngrx/store';
@Component({
selector: 'app-my-component',
templateUrl: 'my-component.component.html'
styleUrls: ['my-component.component.scss']
})
export class MyComponent {
constructor(private readonly store: Store) {}
deleteForm(): void {
this.store.dispatch(storeFormSyncActions.deleteForm({ storeFormSyncId: 'myId'}));
}
}
This library works really well with @larscom/ngrx-store-storagesync
You can persist the state of your forms to localStorage
or sessionStorage
in a few seconds.
import { storeFormSyncKey } from '@larscom/ngrx-store-formsync'; // import storeFormSyncKey
export function storageSyncReducer(reducer: ActionReducer<IRootState>): ActionReducer<IRootState> {
const metaReducer = storageSync<IRootState>({
features: [
{
stateKey: storeFormSyncKey, // add storeFormSync as feature
deserialize: (featureState: string) => JSON.parse(featureState) // override the deserializer if you are gonna use `Date` objects
}
],
storage: window.localStorage // persist to localStorage
});
return metaReducer(reducer);
}
Head over to @larscom/ngrx-store-storagesync on how to configure that library.