2017-02-19 48 views
6

我的計劃是在我的ngrx商店中存儲表單的值,以允許我的用戶在網站周圍導航並返回到表單,如果他們希望。這個想法是,表單的值將使用可觀察值從商店重新填充。如何使用Observable初始化Reactive Angular2表單?

這裏是如何我目前做:

constructor(private store: Store<AppState>, private fb: FormBuilder) { 
    this.images = images; 
    this.recipe$ = store.select(recipeBuilderSelector); 
    this.recipe$.subscribe(recipe => this.recipe = recipe); // console.log() => undefined 
    this.recipeForm = fb.group({ 
     foodName: [this.recipe.name], // also tried with an OR: (this.recipe.name || '') 
     description: [this.recipe.description] 
    }) 
    } 

這家店給我看到通過我的選擇正常工作經過一個初始值,而是由我的時間創建窗體,我不我認爲這個價值已經回來了。因此this.recipe仍未定義。

這是錯誤的方法,或者我可以以某種方式確保在創建表單之前返回observable?

回答

3

我能想到的兩個選項...

選項1:

使用的HTML的*ngIf顯示形式類似

<form *ngIf="this.recipe">...</form> 

選項2: 在您的模板中使用async管道並創建您的模型,如:

組件

model: Observable<FormGroup>;  
... 
this.model = store.select(recipeBuilderSelector) 
    .startWith(someDefaultValue) 
    .map((recipe: Recipe) => { 
     return fb.group({ 
      foodName: [recipe.name], 
      description: [recipe.description] 
     }) 
    }) 

模板

<app-my-form [model]="(model | async)"></app-my-form> 

你將不得不考慮如何處理更新的存儲和當前模型。

+1

我無法通過這種方式得到它。 '類型Observable'上不存在startsWith()。該函數似乎只存在於字符串中。 –

+0

對不起,該方法應該是'startWith'。 https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/startwith。md – shusson

+0

'.startWith()'在第一次迭代中工作,但是當第二次(dev模式)運行時,它再次未定義。我通過刪除'startWith()'並將選擇器更改爲:'return _.cloneDeep(state.recipebuilder)|| someDefaultValue;' –

5

雖然增加另一層似乎更復雜,它是由單個組件分成兩個處理觀測要容易得多:一個容器組件和表象組件。

容器組件僅處理observables而不處理演示文稿。從任何可觀察的數據通過@Input屬性傳遞到呈現組件和async管用於:

@Component({ 
    selector: "recipe-container", 
    template: `<recipe-component [recipe]="recipe$ | async"></recipe-component>` 
}) 
export class RecipeContainer { 

    public recipe$: Observable<any>; 

    constructor(private store: Store<AppState>) { 
    this.recipe$ = store.select(recipeBuilderSelector); 
    } 
} 

的表象的組件接收簡單的屬性,並且不具有處理觀測:

@Component({ 
    changeDetection: ChangeDetectionStrategy.OnPush, 
    selector: "recipe-component", 
    template: `...` 
}) 
export class RecipeComponent { 

    public recipeForm: FormGroup; 

    constructor(private formBuilder: FormBuilder) { 
    this.recipeForm = this.formBuilder.group({ 
     foodName: [""], 
     description: [""] 
    }); 
    } 

    @Input() set recipe(value: any) { 
    this.recipeForm.patchValue({ 
     foodName: value.name, 
     description: value.description 
    }); 
    } 
} 

使用容器和表示組件的概念是一個通用的Redux概念,在Presentational and Container Components中進行了說明。

+0

我無法通過這種方式爲我工作。不知何故,表格在選擇器被稱爲 –

+0

之前正在構建。是的,我明白了你的觀點。我應該在構造函數中創建了表單,並且僅在@ @ Input被更改時才應用這些更改。我已經更新了答案。無論您決定採用何種方式,我都鼓勵您考慮將容器和演示組件分離,因爲它確實讓生活更輕鬆。 – cartant

+0

任何批評或舒鬆的選擇2答案?我可以在沒有容器的情況下使用'[formGroup] =「recipe $ | async」' –