39 votes

Angular 2 + ngrx(redux) + formulaires

Comment gérer les formulaires Angular 2 dans un flux de données unidirectionnel ? En particulier avec la validation entre plusieurs composants parents/enfants ?

J'utilise ngrx/store et des formulaires pilotés par modèle avec form builder Est-il possible de faire quelque chose de similaire à un réducteur de formulaire dans React et de l'intégrer à Store ?

Avez-vous des articles à ce sujet ?

15voto

MrWolfZ Points 146

J'ai créé une bibliothèque appelée ngrx-forms qui fait exactement ce que vous voulez. Vous pouvez l'obtenir sur npm via :

npm install ngrx-forms --save

Je vous recommande de consulter le README complet sur la page github, mais vous trouverez ci-dessous quelques exemples de ce que vous devez faire pour que la bibliothèque soit opérationnelle une fois installée.

Importez le module :

import { StoreModule } from '@ngrx/store';
import { NgrxFormsModule } from 'ngrx-forms';

import { reducers } from './reducer';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    NgrxFormsModule,
    StoreModule.forRoot(reducers),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Ajoutez un état de groupe quelque part dans votre arbre d'état via createFormGroupState et appeler le formGroupReducer à l'intérieur de votre réducteur :

import { Action } from '@ngrx/store';
import { FormGroupState, createFormGroupState, formGroupReducer } from 'ngrx-forms';

export interface MyFormValue {
  someTextInput: string;
  someCheckbox: boolean;
  nested: {
    someNumber: number;
  };
}

const FORM_ID = 'some globally unique string';

const initialFormState = createFormGroupState<MyFormValue>(FORM_ID, {
  someTextInput: '',
  someCheckbox: false,
  nested: {
    someNumber: 0,
  },
});

export interface AppState {
  someOtherField: string;
  myForm: FormGroupState<MyFormValue>;
}

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

export function appReducer(state = initialState, action: Action): AppState {
  const myForm = formGroupReducer(state.myForm, action);
  if (myForm !== state.myForm) {
    state = { ...state, myForm };
  }

  switch (action.type) {
    case 'some action type':
      // modify state
      return state;

    default: {
      return state;
    }
  }
}

Exposez l'état du formulaire à l'intérieur de votre composant :

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { FormGroupState } from 'ngrx-forms';
import { Observable } from 'rxjs/Observable';

import { MyFormValue } from './reducer';

@Component({
  selector: 'my-component',
  templateUrl: './my-component.html',
})
export class MyComponent {
  formState$: Observable<FormGroupState<MyFormValue>>;

  constructor(private store: Store<AppState>) {
    this.formState$ = store.select(s => s.myForm);
  }
}

Définissez les états de contrôle dans votre modèle :

<form novalidate [ngrxFormState]="(formState$ | async)">
  <input type="text"
         [ngrxFormControlState]="(formState$ | async).controls.someTextInput">

  <input type="checkbox"
         [ngrxFormControlState]="(formState$ | async).controls.someCheckbox">

  <input type="number"
         [ngrxFormControlState]="(formState$ | async).controls.nested.controls.someNumber">
</form>

9voto

jpetitte Points 195

Il s'agit d'une question assez ancienne, mais je n'ai pas pu trouver une grande solution dans ma propre quête pour travailler avec ngrx + formulaires réactifs dans Angular. Par conséquent, je vais poster ma recherche ici avec l'espoir qu'elle puisse aider quelqu'un d'autre. Ma solution peut être décomposée en deux parties, et je prie pour que vous (oh âme altérée) la trouviez applicable à votre problème :

1) Surveiller le ou les éléments du formulaire (par exemple, l'événement "keyup" pour une entrée de texte typique), et mettre à jour l'état à partir de cet événement. Cette stratégie est directement issue de la stratégie composant de recherche de livres en el exemple d'application ngrx . Nous pouvons maintenant remplir avec succès l'état au fur et à mesure que notre formulaire change. Génial ! 50% de réussite !

2) L'angle Guide des formulaires réactifs démontre la création du groupe de formulaires dans le constructeur. J'ai vu d'autres personnes le faire dans ngOnInit, mais c'est trop tard dans le cycle de vie pour nos besoins (j'ai essayé, j'ai échoué). Maintenant que nous avons établi notre groupe de formulaires, configurez ngOnChanges pour capturer tous les changements poussés depuis l'état, puis mettez à jour le groupe de formulaires en utilisant Valeur du patch . Par exemple :

  ngOnChanges(changes: SimpleChanges) {
    if (changes.valueICareAbout1) {
      this.myForm.patchValue({
        valueICareAbout1: changes.valueICareAbout1.currentValue
      });
    }
    if (changes.valueICareAbout2) {
      this.myForm.patchValue({
        valueICareAbout2: changes.valueICareAbout2.currentValue
      });
    }
  }

4voto

Lying Dog Points 1057

Dans les applications que j'ai construites avec Angular 2, la ligne directrice suivante semblait bien fonctionner :

Les composants parents transmettent les données aux enfants via la liaison de données. Les composants enfants demandent des modifications de données en émettant des événements de sortie vers les composants parents. Il incombe aux composants parents d'agir en conséquence.

Dans une structure de composants hiérarchiques, les modifications de données sont traitées par le composant le plus bas qui dépend des données. S'il y a un autre composant plus haut ou un composant frère qui dépend du même élément de données, il faut transmettre les changements en émettant des événements et laisser le traitement à un composant plus haut.

Ce schéma fonctionne bien car, pour toute donnée qui concerne plus d'un composant, un seul composant est chargé d'effectuer les modifications. Les modifications sont automatiquement répercutées. Les composants sont réutilisables et les modifications apportées à l'arbre des composants peuvent être facilement adaptées.

En ce qui concerne la validation, n'importe quel composant dans l'échelle entre le composant le plus bas qui émet une demande de modification de données et le composant le plus haut qui traite finalement la modification, n'importe quel composant peut effectivement annuler la modification en ne la transmettant pas au niveau supérieur. Dans la plupart des applications, j'opterais cependant pour la validation des changements de données à l'origine du changement.

Naturellement, les composants enfants peuvent toujours avoir un état interne et ne doivent pas communiquer les changements - sauf si les changements concernent le composant parent.

3voto

Jim Points 1635

Les données de formulaire sont par nature un état très local, surtout pour Angular puisque ngModel se lie aux variables locales des composants. Les meilleurs développeurs que je connais recommandent de garder les données du formulaire localisées à ce composant (c'est-à-dire d'utiliser ngModel avec des variables locales). En effet, les données de formulaire non soumises ne sont presque jamais partagées par divers composants dans l'ensemble de votre application. Lorsque l'utilisateur soumet le formulaire, vous pouvez envoyer une action avec une charge utile contenant les données du formulaire à un composant parent, au magasin, ou même à un ngrx/effet pour être envoyé à un serveur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X