Компонент Angular 2 — form group

#angular #angular2-forms

#угловой #angular2-формы

Вопрос:

Я пытаюсь создать форму, управляемую данными, с входными данными, поступающими от другого компонента, например:

 <form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
    <app-form-group [name]="name"></app-form-group>
    <app-form-group [name]="email"></app-form-group>
    <app-form-group [name]="other"></app-form-group>
</form>
  

app-form-group Компонент будет выглядеть примерно так:

 <div class="form-group">
    <label class="col-md-2 control-label">{{Name}}</label>
    <div class="col-md-9">
  <input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
  

Проблема в том, что formControlName требуется formGroup директива, поэтому я получаю эту ошибку:

 Error : Error in ./FormGroupComponent class FormGroupComponent - inline template:3:58 caused by: formControlName must be used with a parent formGroup directive.You'll want to add a formGroup
   directive and pass it an existing FormGroup instance (you can create one in your class).
  

Есть ли какой-нибудь способ обойти эту проблему?

Комментарии:

1. Вам нужно будет реализовать свой собственный ControlValueAccessor , как указано здесь blog.thoughtram.io/angular/2016/07/27 /…

Ответ №1:

Вы должны использовать свою FormGroup [formGroup]="signupForm" в app-form-group компоненте.Вы можете использовать этот код :

 <div class="form-group" [formGroup]="signupForm">
  <label class="col-md-2 control-label">{{Name}}</label>
  <div class="col-md-9">
  <input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
  

Комментарии:

1. Как это может signupForm быть видно из app-form-group дочернего компонента? Разве вам не нужно передавать его в явном виде, как в ответе Бернхарда Хохгаттерера?

2. Вы должны отправить «Signuoform» в качестве входных данных

Ответ №2:

Вы можете использовать свойство @Input, чтобы получить ссылку на подкомпонент:

app-form-group.ts:

 @Input('group')
public signupForm: FormGroup;
  

app.html:

 <form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
    <app-form-group [name]="name" [group]="signupForm"></app-form-group>
    <app-form-group [name]="name" [group]="signupForm"></app-form-group>
    <app-form-group [name]="name" [group]="signupForm"></app-form-group>
</form>
  

app-form-group.html:

 <div class="form-group" [formGroup]="signupForm">
   <label class="col-md-2 control-label">{{Name}}</label>
   <div class="col-md-9">
   <input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
  

Для получения подробной информации ознакомьтесь с этим руководством: https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2

Ответ №3:

Если вы хотите реализовать пользовательский компонент для привязки данных к отдельному значению, правильный угловой способ сделать это — использовать подход, в котором родительское представление указывает либо [formControl] или [formControlName] .

 <app-form-group formControlName="name"></app-form-group>
<app-form-group formControlName="email"></app-form-group>
<app-form-group formControlName="other"></app-form-group>
  

В вашем дочернем элементе управления вам необходимо выполнить следующее:

Сначала добавьте в свое @Component объявление следующего поставщика, чтобы Angular знал, что ваш компонент может работать с [formControlName] / [formControl]

 providers: [
  {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => CountrySelectorComponent),
    multi: true
  }
]
  

Затем класс вашего дочернего компонента должен реализовать ControlValueAccessor интерфейс. Это должен быть полностью рабочий пример, если нет, то дайте мне знать, и я изменю код, я ввел его непосредственно в браузер.

 @Component({
  // Ensure [formControl] or [formControlName] is also specified
  selector: '[formControl] app-form-group, [formControlName] app-form-group',
  templateUrl: './country-selector.component.html',
  styleUrls: ['./country-selector.component.scss'],
  providers: [
    {
      // Provide the value accessor
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CountrySelectorComponent),
      multi: true
    }
  ]
})
export class CountrySelectorComponent implements ControlValueAccessor {
  private value: any;
  private hasHadFocus = false;
  private hasNotifiedTouched = false;
  private propagateChange: any = () => {};
  private propogateTouched: any = () => {};

  public changed(event: any) {
    this.value = event.srcElement.value;
    this.propagateChange(this.value);
  }

  /**
   * Called when (focus) is triggered
   */
  public focused() {
    this.hasHadFocus = true;
  }

  /**
   * Called when (blur) is triggered
   */
  public blurred() {
    if (this.hasHadFocus amp;amp; !this.hasNotifiedTouched) {
      // Only notify once, and only if lost focus after a focus
      this.hasNotifiedTouched = true;
      this.propogateTouched();
    }
  }

  /**
   * Called when a new value is set via code
   * @param obj
   */
  writeValue(obj: any): void {
    this.value = obj;
  }

  /**
   * Register a call back to call when our value changes
   * @param fn
   */
  registerOnChange(fn: any): void {
    this.propagateChange = fn;
  }

  /**
   * Register a call back to call when our value is first touched
   * @param fn
   */
  registerOnTouched(fn: any): void {
    this.propogateTouched = fn;
  }
}
  

Ваш app-form-group шаблон будет выглядеть примерно так

 <div class="form-group">
    <label class="col-md-2 control-label">{{Name}}</label>
    <div class="col-md-9">
    <input class="form-control" (blur)="blurred()" focus="focussed()" change="changed($event)">
</div>
  
  1. Добавьте [formGroup]="signupForm" в каждый из ваших app-form-group экземпляров в главном представлении
  2. Внедрите OnInit в свой app-form-group элемент управления.
  3. Добавьте private controlContainer: ControlContainer в конструктор вашего app-form-group компонента, чтобы Angular внедрил его
  4. Добавьте public form: FormGroup; свойство к своему app-form-group компоненту.
  5. В ngOnInit добавьте следующий код

    это.form = this.ContainerControl.control;

В вашем app-form-group шаблоне вы бы добавили [FormGroup] следующим образом

 <div class="form-group" [formGroup]="form">
    <label class="col-md-2 control-label">{{Name}}</label>
    <div class="col-md-9">
  <input class="form-control" [name]="name" [formControlName]="formCtrlName">
</div>
  

Это метод, который требует наименьшего количества кода, и я бы рекомендовал его, когда вы хотите внедрить составные элементы управления, которые редактируют несколько фрагментов данных (например, адрес).

Из этого блога -> https://mrpmorris.blogspot.co.uk/2017/08/angular-composite-controls-formgroup-formgroupname-reactiveforms.html