Как привязать стейт форм контролов к селекторам ngrx?

Для привязки состояния формы в Angular к селекторам ngrx, следует выполнить несколько шагов.

1. Установите необходимые зависимости:
Angular:

npm install @ngrx/store @ngrx/effects

ngrx:

npm install @ngrx/store @ngrx/effects @ngrx/entity

2. Создайте файлы для действий, редукторов и эффектов:

mkdir app/store
cd app/store
touch form.actions.ts form.reducer.ts form.effects.ts form.selectors.ts

3. В файле form.actions.ts определите действия, которые будут использоваться для изменения состояния формы:

import { createAction, props } from '@ngrx/store';

export const updateInputValue = createAction(
  '[Form] Update Input Value',
  props<{ controlName: string, value: any }>()
);

export const submitForm = createAction(
  '[Form] Submit Form'
);

4. В файле form.reducer.ts создайте начальное состояние и определите редуктор для обработки действий:

import { createReducer, on } from '@ngrx/store';
import { updateInputValue, submitForm } from './form.actions';

export interface FormState {
  inputValue: string;
  // Здесь можно добавить другие поля, соответствующие вашей форме
}

export const initialState: FormState = {
  inputValue: '',
  // Инициализируйте значения других полей по мере необходимости
};

export const formReducer = createReducer(
  initialState,
  on(updateInputValue, (state, { controlName, value }) => {
    return { ...state, [controlName]: value };
  }),
  on(submitForm, (state) => {
    // Обработка отправки формы
    return state;
  })
);

5. В файле form.effects.ts создайте эффекты, которые будут вызывать побочные эффекты при определенных действиях:

import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { map, tap } from 'rxjs/operators';
import { updateInputValue, submitForm } from './form.actions';
import { Router } from '@angular/router';

@Injectable()
export class FormEffects {

  updateInputValue$ = createEffect(() =>
    this.actions$.pipe(
      ofType(updateInputValue),
      map(({ controlName, value }) => {
        // Выполните здесь побочные эффекты в зависимости от состояния формы
      })
    ),
    { dispatch: false }
  );

  submitForm$ = createEffect(() =>
    this.actions$.pipe(
      ofType(submitForm),
      tap(() => {
        // Обработка отправки формы
        this.router.navigate(['/success']); // Пример перенаправления после успешной отправки формы
      })
    ),
    { dispatch: false }
  );

  constructor(
    private actions$: Actions,
    private router: Router
  ) {}
}

6. В файле form.selectors.ts определите селекторы для доступа к состоянию формы:

import { createFeatureSelector, createSelector } from '@ngrx/store';
import { FormState } from './form.reducer';

export const selectFormState = createFeatureSelector<FormState>('form');

export const selectInputValue = createSelector(
  selectFormState,
  (state: FormState) => state.inputValue
);

7. В вашем компоненте импортируйте необходимые модули, селекторы и действия:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { updateInputValue, submitForm } from './store/form.actions';
import { selectInputValue } from './store/form.selectors';

@Component({
  selector: 'app-form',
  template: `
    <input type="text" [value]="inputValue | async" (input)="updateInput($event.target.value)" />

    <button (click)="submit()">Submit</button>
  `
})
export class FormComponent {
  inputValue = this.store.select(selectInputValue);

  constructor(private store: Store) {}

  updateInput(value: string) {
    this.store.dispatch(updateInputValue({ controlName: 'inputValue', value }));
  }

  submit() {
    this.store.dispatch(submitForm());
  }
}

В результате, у вас будет форма, привязанная к состоянию ngrx. Вы сможете обновлять значения полей формы с помощью действий и отслеживать состояние формы с помощью селекторов. Кроме того, вы можете определить побочные эффекты для выполнения дальнейших действий при изменении состояния формы.