Angular 2 + ngrx (redux) + формы
Как вы обрабатываете Angular 2 формы в однонаправленном потоке данных? Особенно с проверкой между несколькими родительскими/дочерними компонентами?
Я использую ngrx/store и управляемые моделью формы с компоновщиком форм. Возможно ли сделать что-то подобное, например, редуктор формы в React, и сделать его частью хранилища?
У вас есть статьи об этом?
Ответы
Ответ 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 для публикации на сервере.