Как инициализировать реактивную форму 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 и объясняется в презентационные и контейнерные компоненты.