Как инициализировать реактивную форму Angular2 с помощью наблюдаемого?
мой план-сохранить значения формы в моем магазине 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]
})
}
хранилище получает начальное значение, которое я видел, проходит через мою функцию селектора должным образом, но к моменту создания моей формы я не думаю, что это значение имеет возвращенный. Поэтому this.recipe
по-прежнему не определено.
это неправильный подход, или я могу как-то гарантировать, что наблюдаемое возвращается перед созданием формы?
2 ответов
Я могу придумать два варианта...
Вариант 1:
использовать *ngIf на html, который отображает форму что-то вроде
<form *ngIf="this.recipe">...</form>
Вариант 2: Используйте асинхронные труба в вашем шаблоне и создать свою модель, как:
компонент
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>
вам придется рассмотреть, как обрабатывать обновления хранить и к текущей модели.
хотя добавление другого слоя может показаться более сложным, гораздо проще иметь дело с наблюдаемыми, разделив один компонент на два: a контейнер и представления компонент.
контейнер компонент имеет дело только с наблюдаемыми, а не с презентацией. Данные из любых наблюдаемых объектов передаются в компонент представления через @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 и объясняется в презентационные и контейнерные компоненты.