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

Nat*_*May 7 observable typescript ngrx reactive-forms angular

我的计划是将表单的值存储在我的ngrx商店中,以允许我的用户浏览网站并返回表单(如果他们愿意).我们的想法是,表单的值将使用可观察对象从商店重新填充.

这是我目前正在做的事情:

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]
    })
  }
Run Code Online (Sandbox Code Playgroud)

商店给出了一个初始值,我已经看到它正确地通过我的选择器函数,但是当我的表单被创建时,我不认为该值已经返回.因此this.recipe仍未定义.

这是错误的方法,还是我能以某种方式确保在创建表单之前返回observable?

car*_*ant 8

虽然添加另一层可能看起来更复杂,但通过将单个组件拆分为两个来处理可观察对象要容易得多:容器组件和表示组件.

容器组件仅处理可观察对象而不处理演示文稿.来自任何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);
  }
}
Run Code Online (Sandbox Code Playgroud)

表示组件接收简单属性,而不必处理可观察对象:

@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
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

使用容器和表示组件的概念是一般的Redux概念,并在演示和容器组件中进行了解释.

  • 您绝对可以在没有容器/演示分离的情况下使其工作,但我发现分离对较大的应用程序有益。由您决定在您的情况下是否值得。这只是需要注意的事情;几乎总是有多种方法可以完成某件事。我将容器组件用于所有存储和服务交互,而让表示组件处理简单的输入。顺便说一句,我简化了使用 `@Input` setter 而不是 `OnChanges` 的答案。 (2认同)

shu*_*son 6

我可以想到两个选择...

选项1:

在 html 上使用*ngIf来显示类似的表单

<form *ngIf="this.recipe">...</form>
Run Code Online (Sandbox Code Playgroud)

选项 2:在模板中 使用异步管道并创建模型,如下所示:

成分

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

模板

<app-my-form [model]="(model | async)"></app-my-form>
Run Code Online (Sandbox Code Playgroud)

您必须考虑如何处理商店和当前模型的更新。