Using Angular 4.x I created dynamic forms. (Which allow adding or removing fields depending on the situation.) Everything was just fine in the beginning. All values (start, end, category) have an initial value set in the template. Visually everything looks perfect. The user doesn't need to change anything, if the values were guessed correctly depending on or live synced with other objects on the page.
Issue: If the user doesn't change the values, they all get returned as "" from the form. Despite showing the nice content on the page. Already played a lot around with pristine/dirty and touched flags. Nothing changed.
Finally I found a workaround for the start and the end value. Not very beautiful. Just doing the same date transformation in typescript and setting the start and end values in the formbuilder to the exact same thing. Thought I could then remove the value= from the template to reduce duplicated code. But if I do that, the input field stays empty on the page.
But this workaround cannot work for the category_id thing, which can change live on the page. And even better, the categoriesService.selectedCategory can be none. And we would be interested in the categoriesService.selectedCategory.id field.
The visual thing on the page is done and looks nice. But how can I get these values from the page upon submit? (even when the user didn't play with the values)
This is how my template looks like:
<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>
Typescript (Angular 4.x):
return this.formBuilder.group({
start: this.startDateString,
end: this.endDateString,
category_id: ''
});
And in the save method:
this.presences.value.forEach(presence => {
...
console.log(presence.start);
console.log(presence.category_id);
...
}
More information about startDate and endDate:
// presence default values - declarations
startDate: Date;
startDateString: string;
endDate: Date;
endDateString: string;
and then in a method called on 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');
With reactive forms, things like value
, disabled
and selected
do not work. What you need to do, is to utilize the form controls instead and do what you want with them. Also, with ngbDatepicker
, the value it wants, should be of type NgbDateStruct
which looks like:
{
"year": 2017,
"month": 11,
"day": 22
}
So with the date picker you need to format the date to such that datepicker accepts it, here's a simple sample of how it should look like:
startDateString: NgbDateStruct = {year: new Date().getFullYear(),
month: new Date().getMonth() + 1,
day: new Date().getDate()};
This you will then assign to the form control just like you have.
For the select
, as mentioned, Angular doesn't care about the selected
at all. What you need to do is to use patchValue
(or setValue
) with the value you are getting from service whenever it changes:
this.myNewCustForm.controls.category_id.setValue('some value')
Seems you are using a service for this value. Then maybe use a setter
and getter
for this purpose to set the value to the form control.