Angular 4 动态表单 - 如果未触及则为空值 - 如何获取这些显示的默认值?

Angular 4 dynamic form - empty values if not touched - how to get on these displayed default values?

使用 Angular 4.x 我创建了动态表单。 (允许根据情况添加或删除字段。) 一开始一切都很好。所有值(开始、结束、类别)都在模板中设置了初始值。视觉上一切看起来都很完美。如果根据页面上的其他对象正确猜测值或与页面上的其他对象实时同步,则用户无需更改任何内容。

问题:如果用户不更改值,它们都会从表单中返回为“”。尽管在页面上显示了不错的内容。 已经玩了很多 pristine/dirty 并触及了旗帜。没有任何变化。

最后我找到了起始值和结束值的解决方法。不是很漂亮。只需在 typescript 中执行相同的日期转换,并将 formbuilder 中的开始值和结束值设置为完全相同的值。以为我可以从模板中删除 value= 以减少重复代码。但如果我这样做,页面上的输入字段将保持为空。

但此变通方法不适用于 category_id 东西,它可以在页面上实时更改。更好的是,categoriesService.selectedCategory 可以是 none。我们会对 categoriesService.selectedCategory.id 字段感兴趣。

页面上的视觉效果已经完成,看起来不错。但是如何在提交时从页面中获取这些值呢? (即使用户没有使用这些值)

我的模板是这样的:

<form [formGroup]="myNewCustForm" novalidate (ngSubmit)="save(myNewCustForm)">
...
<label>product</label>
<select class="form-control" formControlName="category_id">
  <option
    *ngFor="let category of categoriesService.categories" 
    [ngValue]="category.id"
    [selected]="categoriesService.selectedCategory ? category.id === categoriesService.selectedCategory.id : false">
      {{category.name}}
    </option>
</select>
...
<label>start</label>
<div class="input-group">
  <input
    class="form-control"
    placeholder="yyyy-mm-dd"
    name="dprestart"
    ngbDatepicker
    #dpstart="ngbDatepicker"
    value="{{startDate | date: 'yyyy-MM-dd'}}"
    formControlName="start"/>
  <button
    class="input-group-addon"
    (click)="dpstart.toggle()"
    type="button">
    <i class="fa fa-calendar" aria-hidden="true"></i>
  </button>
</div>

打字稿 (Angular 4.x):

return this.formBuilder.group({
  start: this.startDateString,
  end: this.endDateString,
  category_id: ''
});

并在保存方法中:

this.presences.value.forEach(presence => {
  ...
  console.log(presence.start);
  console.log(presence.category_id);
  ...
}

关于开始日期和结束日期的更多信息:

// presence default values - declarations
startDate: Date;
startDateString: string;
endDate: Date;
endDateString: string;

然后在调用 ngInit 的方法中:

this.endDate = new Date(Date.now());
this.endDate.setHours(0, 0, 0);
if(this.endDate.getDay() > 4) {
  this.endDate.setDate(this.endDate.getDate()+13-(this.endDate.getDay() || 7));
} else {
  this.endDate.setDate(this.endDate.getDate()+6-(this.endDate.getDay() || 7));
}
this.startDate = new Date(Date.now());
this.startDateString = this.datePipe.transform(this.startDate, 'yyyy-MM-dd');
this.endDateString = this.datePipe.transform(this.endDate, 'yyyy-MM-dd');

对于响应式表单,valuedisabledselected 等内容不起作用。您需要做的是改用表单控件,然后用它们做您想做的事。此外,对于 ngbDatepicker,它想要的值应该是 NgbDateStruct 类型,看起来像:

{
  "year": 2017,
  "month": 11,
  "day": 22
}

因此,对于日期选择器,您需要将日期格式化为日期选择器接受它的格式,下面是一个简单示例,说明它应该是什么样子:

startDateString: NgbDateStruct = {year: new Date().getFullYear(), 
                                  month: new Date().getMonth() + 1, 
                                  day: new Date().getDate()};

然后您将像您一样将其分配给表单控件。

对于 select,如前所述,Angular 根本不关心 selected。您需要做的是将 patchValue(或 setValue)与您从服务中获得的值一起使用,只要它发生变化:

this.myNewCustForm.controls.category_id.setValue('some value')

您似乎正在为此值使用服务。然后可能为此目的使用 settergetter 将值设置为表单控件。