Angular 如何提交带有嵌套组件的角度表单

Angular 如何提交带有嵌套组件的角度表单,angular,typescript,angular7,angular-forms,Angular,Typescript,Angular7,Angular Forms,我有一个dateTime组件,我将在整个应用程序中使用它。我有一个formGroup,我正在使用它提交一个单独组件上的表单,我需要这个组件成为该表单的一部分。我似乎无法从子窗体获取要在父窗体中显示的数据。有没有办法将其设置为父窗体的属性/值 子日期时间选择器HTML: <mat-form-field> <input matInput [ngxMatDatetimePicker]="picker" placeholder="{{ name }}" [formControl]=

我有一个dateTime组件,我将在整个应用程序中使用它。我有一个formGroup,我正在使用它提交一个单独组件上的表单,我需要这个组件成为该表单的一部分。我似乎无法从子窗体获取要在父窗体中显示的数据。有没有办法将其设置为父窗体的属性/值

子日期时间选择器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>
@Input() name: string;
@Input() displayTime: boolean;
@Input() allowDateInPast: boolean;

public dateControl = new FormControl();

constructor() { }

ngOnInit() {

}
<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
});
父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>
@Input() name: string;
@Input() displayTime: boolean;
@Input() allowDateInPast: boolean;

public dateControl = new FormControl();

constructor() { }

ngOnInit() {

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

我通常做的是将FormControl作为输入向下传递。因此,在子组件上有一个输入:
@Input()日期控件:FormControl

在父html中,传递FormControl,如下所示:
既然您希望将
应用程序日期时间选择器
组件用作表单控件,我会确保您实现。这将允许您像使用
一样使用它

您的日期选择器控件将如下所示:

@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>

灵感来源于@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>
最后,父HTML:

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


很高兴回答任何人谁通过这一斗争的问题!我花了比它应该花的时间更长的时间

您应该在日期选择器中实现
ControlValueAccessor
接口。检查这个Stackblitz:我根据这个建立了一个新的答案。你的答案和谷歌搜索的混合最终帮助我解决了这个问题。非常感谢。你应该检查@spots的答案。它比这个好多了。你能帮我理解为什么它更好吗?看起来更简单的答案是这个。是什么让事情变得更糟?