如何使用嵌套组件提交 Angular 表单
How To Submit Angular Form with a Nested Component
我有一个我构建的 dateTime 组件,我将在整个应用程序中使用它。我有一个 formGroup,我用它在一个单独的组件上提交表单,我需要这个组件成为该表单的一部分。我似乎无法从 child 表单中获取数据以显示在 parent 表单中。有没有办法将其设置为 parent 形式的 属性/ 值?
Child 日期时间选择器 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 打字稿:
@Input() name: string;
@Input() displayTime: boolean;
@Input() allowDateInPast: boolean;
public dateControl = new FormControl();
constructor() { }
ngOnInit() {
}
Parent HTML/form:
<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>
Parent 打字稿:
formGroup: FormGroup = new FormGroup({
reportName: new FormControl("", Validators.required),
// ?? something here
});
这可能吗?我需要以某种方式使用@Output() 吗?
感谢您的帮助。
特拉维斯 W-
我通常做的是将 FormControl 作为输入传递下去。所以在子组件上你有一个输入:
@Input() dateControl: FormControl;
在您的父级 html 中,您像这样传递 FormControl:
<app-datetime-picker [dateControl]="formGroup['dateControl'] >
您现在可以像往常一样在父组件中读取 FormControl 的属性。
我也同意其他答案,控制值访问器将是一个很好的解决方案,但实现起来有点困难。
既然您希望 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());
})
}
受@SnorreDan 启发...但这里有一个更完整的答案。
这里是 child 组件 TS:
@Input() dateTime: FormGroup = new FormGroup({
startDate: new FormControl("", Validators.required),
});
constructor() {
this.dateTime = new FormGroup({});
this.dateTime.addControl("startDate", new FormControl());
}
在child 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>
在parent表格组中:
// This is important! It must match what is in the child component.
formGroup: FormGroup = new FormGroup({
startDate: new FormControl("", Validators.required),
});
终于 parent HTML:
<app-datetime-picker [dateTime]="formGroup" [placeholder]="'Start Date'" [endDate]="false" [displayTime]="false" [allowDateInPast]="true"></app-datetime-picker>
很高兴为遇到此问题的任何人回答任何问题!我花了比应该的更长的时间。
我有一个我构建的 dateTime 组件,我将在整个应用程序中使用它。我有一个 formGroup,我用它在一个单独的组件上提交表单,我需要这个组件成为该表单的一部分。我似乎无法从 child 表单中获取数据以显示在 parent 表单中。有没有办法将其设置为 parent 形式的 属性/ 值?
Child 日期时间选择器 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 打字稿:
@Input() name: string;
@Input() displayTime: boolean;
@Input() allowDateInPast: boolean;
public dateControl = new FormControl();
constructor() { }
ngOnInit() {
}
Parent HTML/form:
<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>
Parent 打字稿:
formGroup: FormGroup = new FormGroup({
reportName: new FormControl("", Validators.required),
// ?? something here
});
这可能吗?我需要以某种方式使用@Output() 吗?
感谢您的帮助。
特拉维斯 W-
我通常做的是将 FormControl 作为输入传递下去。所以在子组件上你有一个输入:
@Input() dateControl: FormControl;
在您的父级 html 中,您像这样传递 FormControl:
<app-datetime-picker [dateControl]="formGroup['dateControl'] >
您现在可以像往常一样在父组件中读取 FormControl 的属性。
我也同意其他答案,控制值访问器将是一个很好的解决方案,但实现起来有点困难。
既然您希望 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());
})
}
受@SnorreDan 启发...但这里有一个更完整的答案。
这里是 child 组件 TS:
@Input() dateTime: FormGroup = new FormGroup({
startDate: new FormControl("", Validators.required),
});
constructor() {
this.dateTime = new FormGroup({});
this.dateTime.addControl("startDate", new FormControl());
}
在child 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>
在parent表格组中:
// This is important! It must match what is in the child component.
formGroup: FormGroup = new FormGroup({
startDate: new FormControl("", Validators.required),
});
终于 parent HTML:
<app-datetime-picker [dateTime]="formGroup" [placeholder]="'Start Date'" [endDate]="false" [displayTime]="false" [allowDateInPast]="true"></app-datetime-picker>
很高兴为遇到此问题的任何人回答任何问题!我花了比应该的更长的时间。