Angular2 - Setting date field on reactive form
I have a component that uses two date fields, a start date & and end date.
By default, I have my end date field disabled and I toggle it when they select a start date.
this.transitionForm = this.fb.group({
effectiveEndDate: [{ value: '', disabled: true }]
.....
});
I am trying to set the value of this end date field within my code.
this.transitionForm.controls['effectiveEndDate'].setValue(this.utils.currentDate());
Utility Function:
/**
* Returns the current date
*/
currentDate() {
const currentDate = new Date();
const day = currentDate.getDate();
const month = currentDate.getMonth() + 1;
const year = currentDate.getFullYear();
return month + "/" + day + "/" + year;
}
HTML:
<input type="date" class="form-control input-sm" id="effectiveEndDate" name="effectiveEndDate" placeholder="Required" formControlName="effectiveEndDate">
For some reason, the field is not getting updated though.
I have also tried to use PatchValue
and that wasn't setting it either.
What am I missing?
Solution 1:
When you run this code in Chrome (other browsers not tested) it logs an error to console:
The specified value "7/26/2017" does not conform to the required format, "yyyy-MM-dd".
Which I think describes the problem pretty well
You can fix it by changing your currentDate()
method to something like:
currentDate() {
const currentDate = new Date();
return currentDate.toISOString().substring(0,10);
}
Live plunker example
While this does fix the problem the answer from @JGFMK shows a better way of converting the date using a DatePipe
Solution 2:
FormBuilder.group returns FormGroup:
https://angular.io/api/forms/FormBuilder#group
https://angular.io/api/forms/FormGroup#setValue
Updates:
- Using Angular Pipe in Typescript is discussed here.
-
Discussion for locale:
navigator.language
. - Instantiate a Date Pipe
- Discussion on Dates in Angular.
- Date Pipe docs and source code.
import {DatePipe} from '@angular/common'
...
let dp = new DatePipe(navigator.language);
let p = 'y-MM-dd'; // YYYY-MM-DD
let dtr = dp.transform(new Date(), p);
this.transitionForm.setValue({effectiveEndDate: dtr});
Plunker example (just hit reset)
Solution 3:
Angular has several ways to work with and manage forms. Not all the methods or even all configurations will show a value in the view. I have tried several options and my favorite by far is a reactive form configured like this, as it is simple, clean, flexible, supports validation and will show values in the view.
In your component you need to import FormBuilder
and FormGroup
from @angular/forms
. Optionally you can import Validators
as a way to validate each form field.
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
In the rest of the component we need to define a new variable of type FormGroup: transitionForm: FormGroup
.
Then we need to use constructor injection to make fb
available as FormBuilder
: constructor(public fb: FormBuilder)
, and add field names to our FormBuilder variable: this.transitionForm = fb.group({ ... });
export class EgComponent implements OnInit {
transitionForm: FormGroup;
constructor(public fb: FormBuilder) {
this.transitionForm = fb.group({
'effectiveEndDate': [''],
...
});
}
...
}
You can set the date in many ways. Here we'll just set it using ngInit
ngOnInit() {
const currentDate = new Date().toISOString().substring(0, 10);
this.transitionForm.controls['transitionForm'].setValue(currentDate);
}
For your form you just need is:
<form (ngSubmit)="onSubmit(transitionForm)" [formGroup]="transitionForm" novalidate>
<input type="date" formControlName="effectiveEndDate">
...
<button type="submit" [disabled]="transitionForm.invalid">Submit</button>
</form>
Because this method uses ReactiveForms
you need to make sure to add it to @NgModule
@NgModule({
declarations: [
...
],
imports: [
...,
FormsModule,
ReactiveFormsModule
],
...
Besides making data visible in the view, doing it this way also allows for cleaner html form layout and simple validation. You completely eliminate the need for ngModel and form name tags.
You can pass data to your method directly (ngSubmit)="onSubmit(transitionForm)"
and since it's a FormGroup
your forms data is also available as this.transitionForm.value