Description
I'm trying to wrap the MatDatePicker
in a custom component called MyDatePicker
so that I can use it in the html as the following.
Issue
The dateVariable
is always undefined and seems the two-way binding I implemented below is not working. Once the user selects a new date from the picker, the setter gets called. However, the new value is not binded to the dateVariable
.
Questions
Implementation
HTML file:
<my-datepicker [(selectedDate)]="dateVariable" placeholder="some text"></my-datepicker>
<button (click)="btnClick()">Show Selected Date</button>
The TS file:
//...
dateVariable: string;
btnClick() {
console.log('selected date:', this.dateVariable);
}
//...
MyDatepicker.component.ts
export class MyDatepickerComponent {
dateValue: string;
@Input() placeholder: string;
@Output() dateChange: EventEmitter<string> = new EventEmitter<string>();
@Input()
get selectedDate() {
console.log('getter');
return this.dateValue;
}
set selectedDate(val) {
console.log('setter');
this.dateValue = val;
this.dateChange.emit(this.dateValue);
}
pickerEvent(event: MatDatepickerInputEvent<Date>) {
this.selectedDate = event.value.toISOString();
}
}
MyDatepicker.component.html:
<mat-form-field>
<input matInput [matDatepicker]='pickerDate' placeholder='{{placeholder}}' (dateInput)="pickerEvent($event)">
<mat-datepicker-toggle matSuffix [for]='pickerDate'></mat-datepicker-toggle>
<mat-datepicker #pickerDate></mat-datepicker>
</mat-form-field>
As already stated: For the two-way binding [()]
(banana-in-a-box syntax)
we have to write an @Input
with the corresponding @Output
like:
@Input() selectedDate: Date;
@Output() selectedDateChange: EventEmitter<Date> = new EventEmitter<Date>();
This can be used with an Input-Binding and a separate Output-Binding:
<my-datepicker [selectedDate]="dateVariable" (selectedDateChange)="dateVariable = $event" placeholder="some text"></my-datepicker>
Or with a little syntactic sugar provided by Angular with the banana-in-the-box syntax:
<my-datepicker [(selectedDate)]="dateVariable" placeholder="some text"></my-datepicker>
Aside Notes:
1) I think you need to bind the matInput
with the actual Date
value as well
<mat-form-field>
<input matInput [matDatepicker]='pickerDate' [value]="selectedDate" placeholder='{{placeholder}}' (dateInput)="pickerEvent($event)">
<mat-datepicker-toggle matSuffix [for]='pickerDate'></mat-datepicker-toggle>
<mat-datepicker #pickerDate></mat-datepicker>
</mat-form-field>
2) If you want to use my-datepicker
inside of an Angular form you need to implement the ControlValueAccessor
interface
3) If the only reason you are writing this custom component is that you want to use an ISO date string as input I would suggest handling this transformation on an API / Service level instead of in a component.