angular - Bir Observable kullanarak Reactive Angular2 formunu nasıl başlatabilirim?


Benim planım, kullanıcılarımın site içinde dolaşıp istediklerinde forma geri dönebilmelerini sağlamak için bir formun değerlerini ngrx mağazamda saklamak. Fikir, formun değerlerinin bir gözlemlenebilir (observable) kullanılarak mağazadan yeniden doldurulması olacak.

işte bunu şu anda nasıl yaptığım:

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

Mağazaya başlangıç değeri veriliyor, ve bu değerin seçici fonksiyonumdan düzgün bir şekilde geçtiğini gördüm, ancak formum oluşturulduğunda, bu değerin geri dönmediğini düşünüyorum. Bu nedenle this.recipe hâlâ tanımsız.

Bu yanlış bir yaklaşım mı, yoksa formu oluşturmadan önce gözlemlenebilirin döndürüldüğünden nasıl emin olabilirim?

Cevap #1

Başka bir katman eklemek daha karmaşık görünse de, tek bir bileşeni ikiye ayırarak gözlemlenebilirlerle başa çıkmak çok daha kolaydır: bir kapsayıcı bileşen ve bir gösterim bileşeni.

Kapsayıcı bileşen yalnızca gözlemlenebilirlerle ilgilenir ve sunumla ilgilenmez. Herhangi bir gözlemlenebilirden gelen veriler, @Input özellikleri aracılığıyla sunum bileşenine geçirilir ve async pipe kullanılır:

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

Sunum bileşeni basit özellikler alır ve gözlemlenebilirlerle ilgilenmek zorunda değildir:

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

Kapsayıcı (container) ve sunumsal (presentational) bileşenleri kullanma kavramı genel bir Redux konseptidir ve Sunumsal ve Kapsayıcı Bileşenler başlığında açıklanmıştır.

Cevap #2

Aklıma iki seçenek geliyor...

Seçenek 1:

Formu gösteren HTML'de *ngIf kullanın, şöyle bir şey

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

Seçenek 2: Şablonunuzda async borusunu kullanın ve modelinizi şu şekilde oluşturun:

bileşen

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

şablon

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

Mağaza ve mevcut modeldeki güncellemeleri nasıl ele alacağınızı düşünmeniz gerekecek.

İlgili makaleler