angularreduxngrxngrx-forms

Angular Ngrx-Forms Async Pipe Could not be found error


I want to manage the state of my form using ngrx-forms library; so following docs: https://ngrx-forms.readthedocs.io/en/master/

i have a reducer:

import { Action, createReducer } from '@ngrx/store';
import {
  FormGroupState,
  createFormGroupState,
  formGroupReducer,
  onNgrxForms,
} from 'ngrx-forms';
import { Gender } from '../../core/enums/gender_enum';

// 1. Definicja modelu danych formularza
export interface PatientFormValue {
  name: string;
  last_name: string;
  age: number;
  gender: Gender;
}
// 2. Początkowy stan formularza
const FORM_ID = 'PatientFormValue';
const initialFormState = createFormGroupState<PatientFormValue>(FORM_ID, {
  name: '',
  last_name: '',
  age: 0,
  gender: Gender.nie_podawać,
});

// 3. Definicja stanu aplikacji
export interface PatientDataState {
  someOtherField: string;
  myForm: FormGroupState<PatientFormValue>;
}

const initialState: PatientDataState = {
  someOtherField: '',
  myForm: initialFormState,
};

// 4. Reducer zwiazany a formularzem
export function patientFormReducer(
  state = initialState,
  action: Action,
): PatientDataState {
  const myForm = formGroupReducer(state.myForm, action);
  if (myForm !== state.myForm) {
    state = { ...state, myForm };
  }
  switch (action.type) {
    case 'some action type':
      return state;
    default: {
      return state;
    }
  }
}

export function reducer(state: PatientDataState | undefined, action: Action) {
  return patientFormReducer(state, action);
}

then the app html:

<ng-container *ngIf="formState$ | async as formState">
  <form novalidate [ngrxFormState]="formState">
    <input
      type="text"
      [ngrxFormControlState]="formState.controls.someTextInput"
    />

    <input
      type="checkbox"
      [ngrxFormControlState]="formState.controls.someCheckbox"
    />

    <input
      type="number"
      [ngrxFormControlState]="formState.controls.nested.controls.someNumber"
    />
  </form>
</ng-container>

and compontent.ts

import { Component } from '@angular/core';
import { OverviewNavComponent } from '../overview-nav/overview-nav.component';
import { RouterLink, Router, ActivatedRoute } from '@angular/router';
// store
import { Store, StoreModule } from '@ngrx/store';
import { FormGroupState, NgrxFormsModule, setValue } from 'ngrx-forms';
// icons
import { NgIconComponent, provideIcons } from '@ng-icons/core';
import {
  bootstrapArrowRightCircleFill,
  bootstrapArrowLeftCircleFill,
} from '@ng-icons/bootstrap-icons';
import { Observable } from 'rxjs';
import {
  PatientDataState,
  PatientFormValue,
} from '../../../../store/patient-store/patients.reducer';

@Component({
  selector: 'app-patients-data',
  standalone: true,
  imports: [
    NgIconComponent,
    OverviewNavComponent,
    RouterLink,
    NgrxFormsModule,
    StoreModule,
  ],
  templateUrl: './patients-data.component.html',
  styleUrl: './patients-data.component.css',
  viewProviders: [
    provideIcons({
      bootstrapArrowRightCircleFill,
      bootstrapArrowLeftCircleFill,
    }),
  ],
})
export class PatientsDataComponent {
  formState$: Observable<FormGroupState<PatientFormValue>>;

  constructor(
    private router: Router,
    private activatedRoute: ActivatedRoute,
    private store: Store<PatientDataState>,
  ) {
    this.formState$ = store.select((s) => s.myForm);
  }

  // updateFormValue(newValue: PatientFormValue) {
  //   this.store.dispatch(setValue({ value: newValue }));
  // }
}

For now, when i access the component i get error console:

 The pipe 'async' could not be found

so i add import:

CommonModule 

and then i get:

Property 'someTextInput' does not exist on type 'FormGroupControls<PatientFormValue>'.

Another problem is using

<ng-container *ngIf="formState$ | async as formState">

as I am using Angular17 and i am not sure if cant switch to:

@if(formState$ | async as formState){ }

When i import the CommonModule i get multiple errors but i fix the pipe problem. Without CommonModule i get pipe problem but the form seems to work. How to save and retrive data to ngrx Store using ngrx forms and Angular 17? How to fix async pipe problem?

I tried adding and removing CommonModule and rewriting the @if statement. Also, i dont really understand how to manipulate data- change the data on change() using this library.

edit: after adding CommonModule i have now:

inject() must be called from an injection context such as a constructor, a factory function, a field initializer

Solution

  • Async pipe is something that needs to be imported to be used.

    When working with standalone components you can see standalone: true set on the component decorator.

    You can either import AsyncPipe or CommonModule (contains many directives and pipes, e.g. NgIf, CurrencyPipe, NgFor) from '@angular/common'.

    ...
    import { CommonModule } from '@angular/common';
    ...
    
    ...
    @Component({
      selector: 'app-patients-data',
      standalone: true,
      imports: [
        CommonModule, // <- changed here!
        NgIconComponent,
        OverviewNavComponent,
        RouterLink,
        NgrxFormsModule,
        StoreModule,
      ],
    ...