【问题标题】:How To Submit Angular Form with a Nested Component如何使用嵌套组件提交 Angular 表单
【发布时间】:2020-02-01 06:44:20
【问题描述】:

我有一个我构建的 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() {

}

父 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() 吗?

感谢您的帮助。
特拉维斯 W-

【问题讨论】:

标签: angular typescript angular7 angular-forms


【解决方案1】:

我通常做的是将 FormControl 作为输入向下传递。所以在子组件上你有一个输入: @Input() dateControl: FormControl;

在您的父 html 中,您传递 FormControl 如下: &lt;app-datetime-picker [dateControl]="formGroup['dateControl'] &gt;

您现在可以像往常一样在父组件中读取 FormControl 的属性。

我也同意其他答案,控制值访问器将是一个很好的解决方案,但实现起来有点困难。

【讨论】:

  • 我根据这个建立了一个新的答案。您的答案和一些谷歌搜索的混合最终帮助我解决了这个问题。谢谢!
【解决方案2】:

既然您希望将app-datetime-picker 组件用作表单控件,我会确保您实现ControlValueAccessor。这将允许您像使用 &lt;input&gt;&lt;select&gt; 一样使用它。

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

@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());
    })
}

【讨论】:

    【解决方案3】:

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

    很高兴为遇到此问题的任何人回答任何问题!我花了比应有的时间更长的时间。

    【讨论】:

    • 您应该检查@spots 的答案。比这个好多了。
    • 你能帮我理解为什么它更好吗?似乎更简单的答案是这个。是什么让情况变得更糟?
    猜你喜欢
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 2011-10-31
    • 2020-04-05
    • 2014-03-16
    • 2019-03-27
    • 2018-01-11
    • 2016-08-04
    相关资源
    最近更新 更多