Как отправить Angular форму с вложенным компонентом - PullRequest
2 голосов
/ 31 января 2020

У меня есть компонент dateTime, который я построил, и который я собираюсь использовать в приложении. У меня есть formGroup, которую я использую для отправки формы в отдельный компонент, и мне нужно, чтобы этот компонент был частью этой формы. Я не могу получить данные из дочерней формы для отображения в parentForm. Есть ли способ установить это как свойство / значение родительской формы?

Child DateTime Picker HTML:

<mat-form-field>
  <input matInput [ngxMatDatetimePicker]="picker" placeholder="{{ name }}" [formControl]="dateControl" required="true">
  <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
  <ngx-mat-datetime-picker #picker startView="year"></ngx-mat-datetime-picker>
</mat-form-field>

Child Typescript :

@Input() name: string;
@Input() displayTime: boolean;
@Input() allowDateInPast: boolean;

public dateControl = new FormControl();

constructor() { }

ngOnInit() {

}

Родительский HTML / форма:

<form [formGroup]="formGroup">
<mat-label>Name</mat-label>
    <input type="textfield" formControlName="reportName" matInput required="true" placeholder="Report Name" name="reportName">
</mat-form-field>

<div class="col-sm">
    <app-datetime-picker [name]="'Start Date'" [displayTime]="true" [allowDateInPast]="true"></app-datetime-picker>
</div>

<button class="float-right" [disabled]="formGroup.invalid" (click)="createReport()" mat-raised-button color="primary">Save</button>
  </div>
</form>

Родительская машинопись:

formGroup: FormGroup = new FormGroup({

reportName: new FormControl("", Validators.required),
// ?? something here
});

Это возможно? Нужно ли мне каким-либо образом использовать @Output ()?

Спасибо за любую помощь.
Travis W-

Ответы [ 3 ]

2 голосов
/ 31 января 2020

Что я обычно делаю, так это передаю FormControl в качестве ввода. Итак, для дочернего компонента у вас есть вход: @Input() dateControl: FormControl;

В вашем родителе html вы передаете FormControl следующим образом: <app-datetime-picker [dateControl]="formGroup['dateControl'] >

Теперь вы можете читать свойства FormControl в родительском компоненте, как обычно.

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

0 голосов
/ 01 февраля 2020

Вдохновленный @SnorreDan ... но вот более полный ответ.

Вот дочерний компонент TS:

@Input() dateTime: FormGroup = new FormGroup({
    startDate: new FormControl("", Validators.required),
  });


constructor() { 
    this.dateTime = new FormGroup({});
    this.dateTime.addControl("startDate", new FormControl());
  }

В дочернем html:

<mat-form-field>
      <input matInput [ngxMatDatetimePicker]="picker" placeholder="{{ placeholder }}" required="true" formControlName="startDate">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <ngx-mat-datetime-picker #picker startView="year"></ngx-mat-datetime-picker>
</mat-form-field>

В родительской формеГруппа:

 // This is important! It must match what is in the child component.
 formGroup: FormGroup = new FormGroup({
    startDate: new FormControl("", Validators.required),
 });

наконец родитель HTML:

<app-datetime-picker [dateTime]="formGroup" [placeholder]="'Start Date'" [endDate]="false" [displayTime]="false" [allowDateInPast]="true"></app-datetime-picker>

С радостью отвечу на любые вопросы для всех, кто борется за это! Это заняло у меня больше времени, чем следовало.

0 голосов
/ 31 января 2020

Поскольку вы хотите, чтобы ваш app-datetime-picker компонент использовался в качестве элемента управления формой, я должен убедиться, что вы реализуете ControlValueAccessor . Это позволит вам использовать его, как если бы это было что-то вроде <input> или <select>.

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

@Component({
  selector: 'app-datetime-picker',
  templateUrl: './app-datetime-picker.html',
  styleUrls: ['./app-datetime-picker.css'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => DateControlPicker),
      multi: true
    }
  ]
})
export class DateTimePicker implements ControlValueAccessor {
  disabled = false;
  innerValue: Date;

  //Make sure your template calls this function to update the value
  valueChanged(obj: Date) {
    this.writeValue(obj); //save the value so this component can render it
    this.onChangeCallback(obj); //update the form
  }

  //satisfy the ControlValueAccessor interface
  //the forms library will call this when the form is first initialized or when the control is updated by the code "myFormGroup.controls['someControlName'].patchValue(new Date())"
  writeValue(obj: any): void {
    this.selectedValue = obj;
  }

  //Register a callback - this callback function is what we neeed to call to update that form
  registerOnChange(fn: any): void {
    this.onChangeCallback = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouchedCallback = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.disabled = isDisabled;
  }

  private onTouchedCallback: () => void = () => {
  };
  private onChangeCallback: (_: any) => void = () => {
  };
}

Тогда вы можете используйте его в шаблоне, который имеет форму:

<form [formGroup]="myFormGroup">
    <app-datetime-picker formControlName="myControlName"></app-datetime-picker>
</form>

Код для создания группы форм:

constructor(private formBuilder: FormBuilder){}

ngOnInit(){
    this.myFormGroup = this.formBuilder.group({
        myDateControlName: new FormControl(new Date());
    })
}
...