2017-02-19 1 views
6

Mein Plan ist es, die Werte eines Formulars in meinem ngrx-Speicher zu speichern, damit meine Benutzer, wenn sie möchten, auf der Seite und zurück zum Formular navigieren können. Die Idee wäre, dass die Werte der Form aus dem Speicher unter Verwendung eines Observablen wieder aufgefüllt werden.Wie kann ich ein Reactive Angular2 Formular mit einem Observable initialisieren?

hier ist, wie ich mache es zur Zeit:

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

Der Laden ist ein Anfangswert gegeben, die ich richtig meine Auswahlfunktion gesehen durchläuft, sondern durch die Zeit wird meine Form erstellt, ich don Ich glaube nicht, dass der Wert zurückgekehrt ist. Daher ist this.recipe immer noch nicht definiert.

Ist dies der falsche Ansatz, oder kann ich irgendwie sicherstellen, dass das Observable zurückgegeben wird, bevor das Formular erstellt wird?

Antwort

3

ich von zwei Möglichkeiten denken kann ...

Option 1:

Verwenden Sie ein *ngIf auf der HTML-Code, die Form so etwas wie

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

Option 2 zeigt: Verwenden Sie die async Rohr in Ihrer Vorlage und erstellen Sie Ihr Modell wie:

Komponente

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

Vorlage

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

Sie müssten überlegen, wie Updates in den Laden und zum aktuellen Modell zu handhaben.

+1

Ich war nicht in der Lage, es auf diese Weise zu arbeiten. 'startsWith() existiert nicht für den Typ Observable'. Diese Funktion scheint nur für Strings zu existieren. –

+0

Es tut mir leid, die Methode sollte 'startWith' sein. https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/startwith.md – shusson

+0

'.startWith()' arbeitete mit der ersten Iteration, aber als die zweite (dev mode) lief, war sie wieder undefiniert. Ich habe es geschafft, indem ich 'startWith()' lösche und meinen Selektor zu '' return _.cloneDeep (state.recipebuilder) || ändere someDefaultValue; ' –

5

Obwohl eine weitere Ebene hinzugefügt scheinen mag komplizierter, es ist viel einfacher, mit Observablen zu behandeln, indem die einzelne Komponente in zwei aufgeteilt: eine Behälter Komponente und eine Präsentations Komponente.

Die Container-Komponente befasst sich nur mit Observablen und nicht mit der Darstellung. Die Daten von allen Observablen wird über @Input Eigenschaften an die Präsentationskomponente geleitet, und das async Rohr verwendet wird:

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

Die Präsentations-Komponente empfängt einfache Eigenschaften und muss nicht mit Observablen befassen:

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

Der Begriff der Verwendung von Container- und Präsentationskomponenten ist ein allgemeines Redux-Konzept und wird in Presentational and Container Components erläutert.

+0

Ich konnte diesen Weg nicht finden, um für mich zu arbeiten. Irgendwie wurde das Formular erstellt, bevor der Selector –

+0

genannt wurde. Ja, ich verstehe Ihren Standpunkt. Ich hätte das Formular im Konstruktor erstellen und die Änderungen nur anwenden sollen, wenn der '@ Input' geändert wurde. Ich habe die Antwort aktualisiert. Wie auch immer Sie sich dafür entscheiden, ich möchte Sie ermutigen, die Dinge in Container- und Präsentationskomponenten zu unterteilen, da dies das Leben einfacher macht. – cartant

+0

keine Kritik oder Shusson Option 2 Antwort? Ich konnte es ohne einen Container tun, indem ich '[formGroup] = "rezept $ | async" ' –

Verwandte Themen