How can I initialize a Reactive Angular2 form using Observable?

My plan is to store the form values ​​in my ngrx store, to allow my users to navigate the site and return to the form if they so wish. The idea would be that form values ​​would be populated from the store using the observable.

this is how i am doing it now:

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 repository is given the initial value that I saw through my selection function correctly, but by the time my form was created, I did not think that this value had returned. Therefore this.recipe is still undefined.

Is this the wrong approach, or can I somehow make sure that the observable returns before the form is created?

+6
source share
2 answers

I can imagine two options ...

Option 1:

Use * ngIf in html, which displays a form similar to

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

Option 2: Use async in the template and create your model as follows:

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 will need to consider how to handle updates for the repository and the current model.

+3
source

Although adding another layer may seem more complicated, it’s much easier to deal with observables by dividing one component into two: the container component and the presentation component.

The container component deals only with observables, and not with representation. Data from any observables is passed to the view component through the @Input properties and the async pipe is used:

 @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 presented component receives simple properties and does not 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 concept of using container and presentation components is a general Redux concept and is explained in presentation and container components .

+5
source

Source: https://habr.com/ru/post/1015107/


All Articles