2017-02-19 44 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”' –