В: Как использовать форму шаблона Angular 2 с ng-content?

Невозможно ли иметь элементы ввода формы внутри ng-контента и иметь это "соединение" с экземпляром ngForm родительского компонента?

Возьмите этот базовый шаблон для родительского компонента:

<form (ngSubmit)="onSubmit(editForm)" #editForm="ngForm" novalidate>               
<ng-content></ng-content>
<button type="submit">Submit</button>
</form>

Затем внутри дочернего компонента, который помещается внутри "ng-content", что-то вроде этого:

<input type="text" [(ngModel)]="user.firstName" #firstName="ngModel" name="firstName" required minlength="2">

При отправке родительской формы дочерние элементы управления недоступны, что также означает, что грязная/проверка того, что находится в дочернем компоненте, не отображается в родительской форме.

Что здесь отсутствует?

Ответ 1

Есть хороший шанс, что вы на этот раз придумали другое решение, но я просто понял, как это сделать. Надеюсь, это поможет вам или кому-то еще.

import { NgModel } from '@angular/forms';
import { Component, ContentChildren, ViewChild, QueryList, AfterViewInit } from '@angular/core';

@Component({
  selector: 'my-custom-form',
  template: `
    <form (ngSubmit)="onSubmit(editForm)" #editForm="ngForm" novalidate>               
      <ng-content></ng-content>
      <button type="submit">Submit</button>
    </form>
  `,
})
export class MyCustomFormComponent implements AfterViewInit {
  @ContentChildren(NgModel) public models: QueryList<NgModel>;
  @ViewChild(NgForm) public form: NgForm;

  public ngAfterViewInit(): void {
    let ngContentModels = this.models.toArray();
    ngContentModels.forEach((model) => {
      this.form.addControl(model);
    });
  }

  public onSubmit(editForm: any): void {
    console.log(editForm);
  }
}

Затем вы можете использовать его в своем шаблоне следующим образом:

<my-custom-form>
  <input name="projectedInput" ngModel>
</my-custom-form>

При отправке формы вы увидите, что элемент управления projectedInput добавлен в NgForm.

Примечание: Я только пытался добавить проецируемые входы из цикла жизненного цикла AfterViewInit. Это может работать раньше, я не уверен. Также могут возникнуть некоторые проблемы с этим, о которых я не знаю. YMMV.