Blog>
Snippets

Using Akita with Angular Forms

Illustrate the process of integrating Akita state management with Angular reactive forms, including synchronization of form state with the store.
import { Injectable } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { Store, StoreConfig } from '@datorama/akita';

export interface MyFormState {
  name: string;
  email: string;
}

export function createInitialState(): MyFormState {
  return {
    name: '',
    email: '',
  };
}

@Injectable({ providedIn: 'root' })
@StoreConfig({ name: 'myForm' })
export class MyFormStore extends Store<MyFormState> {
  constructor() {
    super(createInitialState());
  }
}
This is a basic Store configuration using Akita for an Angular form. It includes an interface describing the form state, a function to create the initial state, and a class that extends the Akita Store.
import { Injectable } from '@angular/core';
import { MyFormStore, MyFormState } from './my-form.store';
import { Query } from '@datorama/akita';

@Injectable({ providedIn: 'root' })
export class MyFormQuery extends Query<MyFormState> {
  constructor(protected override store: MyFormStore) {
    super(store);
  }
  
  selectFormState$ = this.select();
}
This code defines the Query class for the form store which allows us to select parts of the form state. In this instance, we are selecting the entire form state.
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';
import { MyFormStore } from './store/my-form.store';
import { MyFormQuery } from './store/my-form.query';

@Component({
  selector: 'app-my-form',
  templateUrl: './my-form.component.html',
  styleUrls: ['./my-form.component.css']
})
export class MyFormComponent implements OnInit {
  myForm: FormGroup;

  constructor(private myFormStore: MyFormStore, private myFormQuery: MyFormQuery) {
    this.myForm = new FormGroup({
      name: new FormControl('', Validators.required),
      email: new FormControl('', [Validators.required, Validators.email]),
    });
  }

  ngOnInit(): void {
    this.myFormQuery.selectFormState$.subscribe((formState) => {
      this.myForm.patchValue(formState);
    });

    this.myForm.valueChanges.subscribe((formValues) => {
      this.myFormStore.update(formValues);
    });
  }
}
This Angular component is responsible for initializing the reactive form and handles the synchronization between the form and the store. It subscribes to the form state from the store to update the form and listens to any form changes to update the store in return.
<form [formGroup]="myForm">
  <label for="name">Name</label>
  <input id="name" type="text" formControlName="name">
  <label for="email">Email</label>
  <input id="email" type="email" formControlName="email">
  <button (click)="onSubmit()">Submit</button>
</form>
This HTML template contains a simple reactive form using Angular's formGroup and formControlName directives to bind the form controls to the MyFormComponent's FormGroup instance.
.my-form-component {
  display: flex;
  flex-direction: column;
}

.my-form-component label {
  margin: 5px 0;
}

.my-form-component input {
  padding: 5px;
  margin-bottom: 10px;
}
This CSS provides basic styling for the form component, setting up a flex container and adding margins to labels and padding to input elements for better visual structure.