如何使用 Observable 初始化 Reactive Angular2 表单?
How can I initialize a Reactive Angular2 form using an Observable?
我的计划是将表单的值存储在我的 ngrx 存储中,以允许我的用户在站点中导航并在需要时返回表单。这个想法是表单的值将使用 observable 从商店重新填充。
这是我目前的做法:
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
仍未定义。
这是错误的方法吗,或者我能否以某种方式确保在创建表单之前返回可观察对象?
我可以想到两个选项...
选项 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>
您将不得不考虑如何处理对商店和当前模型的更新。
虽然添加另一层可能看起来更复杂,但通过将单个组件分成两部分来处理可观察对象要容易得多:一个 container 组件和一个 演示 组件。
容器组件只处理可观察对象而不处理表示。来自任何可观察对象的数据都通过 @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 中有解释。
我的计划是将表单的值存储在我的 ngrx 存储中,以允许我的用户在站点中导航并在需要时返回表单。这个想法是表单的值将使用 observable 从商店重新填充。
这是我目前的做法:
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
仍未定义。
这是错误的方法吗,或者我能否以某种方式确保在创建表单之前返回可观察对象?
我可以想到两个选项...
选项 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>
您将不得不考虑如何处理对商店和当前模型的更新。
虽然添加另一层可能看起来更复杂,但通过将单个组件分成两部分来处理可观察对象要容易得多:一个 container 组件和一个 演示 组件。
容器组件只处理可观察对象而不处理表示。来自任何可观察对象的数据都通过 @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 中有解释。