Подтвердить что ты не робот

Angular 2 + ngrx (redux) + формы

Как вы обрабатываете Angular 2 формы в однонаправленном потоке данных? Особенно с проверкой между несколькими родительскими/дочерними компонентами?

Я использую ngrx/store и управляемые моделью формы с компоновщиком форм. Возможно ли сделать что-то подобное, например, редуктор формы в React, и сделать его частью хранилища?

У вас есть статьи об этом?

4b9b3361

Ответ 1

Я создал библиотеку под названием ngrx-forms, которая делает именно то, что вы хотите. Вы можете получить его на npm через:

npm install ngrx-forms --save

Я рекомендую проверить полный README на странице github, но ниже вы можете найти несколько примеров того, что вам нужно сделать, чтобы запустить библиотеку и запустить ее после установки.

Импортировать модуль:

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 { }

Добавьте состояние группы в дерево состояний через createFormGroupState и вызовите formGroupReducer внутри редуктора:

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;
    }
  }
}

Экспозиция состояния формы внутри вашего компонента:

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);
  }
}

Задайте состояния управления в шаблоне:

<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>

Ответ 2

Это довольно старый вопрос, но я не мог найти отличного решения в своем собственном стремлении работать с реактивными формами ngrx + в Angular. В результате я опубликую здесь свои исследования с надеждой, что это может помочь кому-то другому. Мое решение может быть разбито на две части, и я молю вас (о, выветренная душа) найти его применимым к вашей проблеме:

1) Проконтролируйте элемент /s формы (например, событие "keyup" для типичного ввода текста) и обновите состояние из этого события. Эта стратегия происходит прямо из компонента поиска книг в пример приложения ngrx. Теперь мы можем успешно заполнить государство по мере изменения нашей формы. Потрясающие! 50% сделано!

2) angular руководство по реактивным формам демонстрирует создание группы форм в конструкторе. Я видел, как другие люди делают это внутри ngOnInit, но это слишком поздно для жизненного цикла для наших нужд (я пробовал, я провалился). Теперь, когда мы создали нашу группу форм, настройте ngOnChanges, чтобы зафиксировать любые изменения, перенесенные из состояния, а затем обновить группу форм, используя patchValue. Например:

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

Ответ 3

В приложениях, которые я построил с помощью Angular 2, было показано, что следующее руководство работает хорошо:

Родительские компоненты передают данные до детей через привязку данных. Детальные компоненты запрашивают изменения данных, передавая выходные события родительским компонентам. Обязанности родительских компонентов должны действовать соответственно.

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

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

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

Естественно, дочерние компоненты могут по-прежнему иметь внутреннее состояние и не нуждаются в изменении сообщений - если изменения не относятся к родительскому компоненту.

Ответ 4

Данные формы по сути являются очень локальным состоянием, особенно для Angular, поскольку ngModel привязывается к локальным переменным компонента. Главные разработчики, которые, как я знаю, рекомендуют хранить данные для формы, локализованной для этого компонента (т.е. Просто использовать ngModel с локальными переменными). Это связано с тем, что данные незаданной формы почти никогда не используются различными компонентами всего вашего приложения. Когда пользователь отправляет форму, вы можете отправить действие с полезной нагрузкой, содержащей данные формы, в родительский компонент, в хранилище или даже с помощью ngrx/effect для публикации на сервере.