简体   繁体   English

如何使用Observable初始化Reactive Angular2表单?

[英]How can I initialize a Reactive Angular2 form using an Observable?

My plan is to store the values of a form in my ngrx store to allow my users to navigate around the site and back to the form if they wish. 我的计划是将表单的值存储在我的ngrx商店中,以允许我的用户浏览网站并返回表单(如果他们愿意)。 The idea would be that the values of the form would repopulate from the store using an observable. 我们的想法是,表单的值将使用可观察对象从商店重新填充。

here is how I'm doing it currently: 这是我目前正在做的事情:

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

The store is given an initial value which I have seen passes through my selector function properly, but by the time my form is created, I don't think that value has returned. 商店给出了一个初始值,我已经看到它正确地通过我的选择器函数,但是当我的表单被创建时,我不认为该值已经返回。 Therefore this.recipe is still undefined. 因此this.recipe仍未定义。

Is this the wrong approach, or can I somehow ensure that the observable is returned before creating the form? 这是错误的方法,还是我能以某种方式确保在创建表单之前返回observable?

Although adding another layer might seem more complicated, it is much easier to deal with observables by splitting the single component into two: a container component and a presentational component. 虽然添加另一层可能看起来更复杂,但通过将单个组件拆分为两个来处理可观察对象要容易得多: 容器组件和表示组件。

The container component deals only with observables and not with the presentation. 容器组件仅处理可观察对象而不处理演示文稿。 The data from any observables is passed to the presentation component via @Input properties and the async pipe is used: 来自任何observable的数据通过@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);
  }
}

The presentational component receives simple properties and does not have to deal with observables: 表示组件接收简单属性,不必处理可观察对象:

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

The notion of using container and presentational components is a general Redux concept and is explained in Presentational and Container Components . 使用容器和表示组件的概念是一般的Redux概念,并在演示和容器组件中进行了解释。

I can think of two options... 我可以想到两个选择......

Option 1: 选项1:

Use an *ngIf on the html that displays the form something like 在显示表格的html上使用* ngIf

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

Option 2: Use the async pipe in your template and create your model like: 选项2:在模板中使用异步管道并创建模型,如:

component 零件

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

template 模板

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

You would have to consider how to handle updates to the store and to the current model. 您必须考虑如何处理商店和当前模型的更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM