2016-07-29 99 views
32

如何處理單向數據流中的Angular 2表單?特別是在幾個父/子組件之間進行驗證?Angular 2 + ngrx(redux)+表格

我使用NGRX /存儲和模型驅動的形式與表單生成器..是否有可能做類似像反應,使其作爲商店的一部分形式減速的東西嗎?

你有一些關於它的文章嗎?

+2

我正在使用ngrx,但沒有進行表單驗證。我決定離開ngModel去做生意(變異了......)不受阻礙。我使用提交按鈕將數據發送到商店並觸發對其他應用程序的更改 –

+1

您可以將商店與模型驅動的表單結合使用。看看這個偉大的文章:http://blog.thoughtram.io/angular/2016/06/22/model-driven-forms-in-angular-2.html –

+0

我也在尋找一個很好的例子,在表單和ngrx上有大量的教程和博客,但不在一起。 – Seb

回答

4

在我與角2構建的應用程序,以下指導看來效果不錯:

父組件通過數據綁定將數據傳遞到孩子。子組件通過向父組件發送輸出事件來請求數據更改。母公司有責任採取相應的行動。

在分層組件結構中,數據更改由依賴於數據的最低組件處理。如果有更高的一個組件或者一個依賴於相同數據項的兄弟,則通過發送事件來傳遞更改,並將處理留給更高的組件。

此方案效果很好,因爲,因爲這是涉及不止一個組件的任何數據,有負責執行變更單個組件。更改自動下降。組件是可重用的,組件樹中的更改可以很容易地進行調整。

關於驗證,在最低的部件發射一個數據改變請求直到該最後處理變化的最高部件之間的階梯的任何部件,任何組分可以有效地通過不將其傳遞更高向上取消更改。在大多數應用程序中,我會選擇在更改的起源處驗證數據更改。

當然,子組件仍然可以有內部狀態,不需要改動通報 - 除非變化是相關的父組件。

3

表單數據本質上是一個非常本地的狀態,特別是對於Angular,因爲ngModel綁定到本地組件變量。我知道的頂級開發人員建議將表單的數據保存到該組件(即,僅將ngModel與局部變量一起使用)。這是因爲未提交的表單數據在整個應用程序中幾乎不會由各種組件共享。當用戶提交表單時,您可以將包含表單數據的有效內容的操作分派給父組件,存儲,甚至發佈到服務器的ngrx/effect。

+1

是啊?本地化?看看Elm--所有的應用程序部件應該是狀態的形狀 –

+0

在組件之間共享數據只是單個狀態存儲的好處之一。這不能是一個完整的答案。 –

+0

@YuriyYakovenko在應用程序級別的狀態中,不需要將與應用程序的一個遠程角落相關的內容保存起來。這不是關於榆樹的追求。這是一個關於Angular 2的問題,Angular 2處理表單的方式幾乎必須綁定到控制器中的事物 - 即本地狀態。 – Jim

5

這是一個相當古老的問題,但我找不到我自己追求的理想解決方案用於在角NGRX +活性形式的合作。因此,我會在這裏發表我的研究成果,希望它能幫助別人。我的解決方案可以分解爲兩部分,我祈禱你(哦風化的靈魂)發現它適用於你的問題:

1)監視表單元素/ s(例如,「keyup」事件的典型文本輸入),並從該事件更新狀態。該策略直接來自ngrx example app中的book search component。我們現在可以在形式發生變化時成功填充國家。真棒! 50%完成!

2)的角reactive forms guide演示創建在構造形式組。我已經看到其他人在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 
     }); 
    } 
    } 
+0

這很有幫助,謝謝! – John

8

我創建了一個名爲ngrx-forms的庫,它完全符合您的需求。您可以通過得到它NPM:

npm install ngrx-forms --save 

我建議您查看GitHub的頁面上滿README,但下面你可以找到你需要做的就是圖書館和運行一次安裝的一些例子。

導入模塊:

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

設置控制器ol狀態:

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

只想說...我喜歡這個圖書館 - 感謝分享! – Drammy