Reputation: 265
I have DatePickerRange of Angular Material and I want to run a function when changing the value in DatePicker I tried with the function (change) but it did not work I would be happy for your help how to do it. Thank you!
This is my html:
<mat-form-field class="form-field">
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [formGroup]="range" [rangePicker]="picker">
<input matStartDate formControlName="start" placeholder="Start date">
<input matEndDate formControlName="end" placeholder="End date">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
<mat-error *ngIf="range.controls.start.hasError('matStartDateInvalid')">Invalid start date
</mat-error>
<mat-error *ngIf="range.controls.end.hasError('matEndDateInvalid')">Invalid end date
</mat-error>
</mat-form-field>
And that's the function I want to activate:
@Output() newItemEvent = new EventEmitter<bookedDate>();
addNewDate() {
this.dateRange.dateStart = this.range.get('start').value;
this.dateRange.dateEnd = this.range.get('end').value;
this.newItemEvent.emit(this.dateRange);
}
Upvotes: 14
Views: 41958
Reputation: 409
The solution I found is to subscribe to the formEnd date control with valueChanges and then recover the value of the formStart date control and check if both are not null before lauch any function. So the code may look like:
this.dateRange.get('end').valueChanges.subscribe( (endDate: Moment) => {
const startDate = this.range.get('start').value;
if (startDate && endDate) {
this.doSomething()
}
})
Upvotes: 0
Reputation: 6235
Though Matt's answer is a good one, the downside with that approach is that (dateChange)
fires only on the endDate input change. E.g if user changes startDate by typing, his event won't fire.
I ended up using Subject
's to combine the Observables from both inputs. This lets me listen when each individual input was changed. Either by picker, or by typing. By checking value
carried by the Event we can determine when user has finished picking both valid dates.
<mat-form-field appearance="fill">
<mat-label>Travel date</mat-label>
<mat-date-range-input [rangePicker]="picker">
<input matStartDate placeholder="Start date" (dateChange)="startDatePicker.next($event)">
<input matEndDate placeholder="End date" (dateChange)="endDatePicker.next($event)">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>
TS:
startDatePicker = new Subject<MatDatepickerInputEvent<any>>();
endDatePicker = new Subject<MatDatepickerInputEvent<any>>();
ngOnInit(): void {
const dateChange$ = combineLatest([this.startDatePicker, this.endDatePicker]).pipe(
map(([a$, b$]) => ({
start: a$,
end: b$
}))
);
dateChange$.subscribe((data) => {
if (data.start.value && data.end.value) {
console.log('User has picked both ranges!');
}
});
}
Upvotes: 3
Reputation: 30
I have used (dateChange)="function()"
to trigger the change in date in mat date picker
Upvotes: 1
Reputation: 49
I faced this problem myself, here is the solution that helped me: component.ts:
import * as moment from 'moment';
import { FormControl, FormGroup } from "@angular/forms";
import { DateAdapter, MAT_DATE_FORMATS, MatDateFormats } from "@angular/material/core";
import { MomentDateAdapter } from '@angular/material-moment-adapter';
const CUSTOM_DATE_FORMATS: MatDateFormats = {
parse: {
dateInput: 'D/MM/YYYY'
},
display: {
dateInput: 'DD/MM/YYYY',
monthYearLabel: 'MMMM Y',
dateA11yLabel: 'LL',
monthYearA11yLabel: 'MMMM Y'
}
};
@Component({
providers: [
{provide: MAT_DATE_FORMATS, useValue: CUSTOM_DATE_FORMATS},
{provide: DateAdapter, useClass: MomentDateAdapter}
],
})
@ViewChild('picker') picker: any;
dateRange: moment.Moment;
disabled = false;
tempDate = new Date().setMonth(new Date().getMonth() - 1);
range = new FormGroup({
start: new FormControl(new Date(this.tempDate)),
end: new FormControl(new Date()),
});
ngAfterViewInit() {
this.range.valueChanges.pipe(
debounceTime(200)
).subscribe(event => {
if (event.start && event.end) {
this.onDateChanged(event);
}
});
}
<mat-form-field class="date-range" appearance="fill">
<mat-label>Enter a date range</mat-label>
<mat-date-range-input
[formGroup]="range"
[rangePicker]="picker">
<input matStartDate formControlName="start" placeholder="Start date">
<input matEndDate formControlName="end" placeholder="End date">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
<mat-error *ngIf="range.controls.start.hasError('matStartDateInvalid')">Invalid start date</mat-error>
<mat-error *ngIf="range.controls.end.hasError('matEndDateInvalid')">Invalid end date</mat-error>
</mat-form-field>
Upvotes: 4
Reputation: 4074
My approach was to add template reference variables to the inputs for matStartDate
and matEndDate
. These are dateRangeStart
and dateRangeEnd
in the template example below:
// Template
<mat-form-field appearance="standard">
<mat-label>{{reportField.value.label}}</mat-label>
<mat-date-range-input [rangePicker]="dateRangePicker">
<input matStartDate
placeholder="Start date"
#dateRangeStart>
<input matEndDate
placeholder="End date"
#dateRangeEnd
(dateChange)="dateRangeChange(dateRangeStart, dateRangeEnd)">
</mat-date-range-input>
<mat-datepicker-toggle matPrefix
[for]="dateRangePicker">
</mat-datepicker-toggle>
<mat-date-range-picker #dateRangePicker></mat-date-range-picker>
</mat-form-field>
The values of these inputs can then be accessed by a function called by the dateChange
output on matEndDate
.
// Component
dateRangeChange(dateRangeStart: HTMLInputElement, dateRangeEnd: HTMLInputElement) {
console.log(dateRangeStart.value);
console.log(dateRangeEnd.value);
}
This avoids the need for a dateChange
event on both inputs.
Upvotes: 54
Reputation: 265
@Kirubel and @Irad Amri Thanks!
It works for me in the end this way:
HTML-
<mat-form-field class="form-field">
<mat-label>Enter a date range</mat-label>
<mat-date-range-input [formGroup]="range" [rangePicker]="picker">
<input **(dateInput)="addEvent('input', $event)"
(dateChange)="addEvent('change', $event)"** matStartDate
formControlName="start" placeholder="Start date">
<input **(dateInput)="addNewDate('input', $event)"
(dateChange)="addNewDate('change', $event)"** matEndDate
formControlName="end" placeholder="End date">
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
<mat-error *ngIf="range.controls.start.hasError('matStartDateInvalid')">Invalid
start date
</mat-error>
<mat-error *ngIf="range.controls.end.hasError('matEndDateInvalid')">Invalid end
date
</mat-error>
</mat-form-field>
TS-
@Output() newItemEvent = new EventEmitter<bookedDate>();
addNewDate(type: string, event: MatDatepickerInputEvent<Date>) {
this.dateRange.dateStart = this.range.get('start').value;
this.dateRange.dateEnd = this.range.get('end').value;
this.newItemEvent.emit(this.dateRange);
}
And again, thanks so much for the help!
Upvotes: 0
Reputation: 19
i have something similar to your problem it works for me so i hope it can help you or give your a hint about a solution here is my html :
<mat-form-field class="dialogform">
<mat-label>Duree du Session : </mat-label>
<input matInput
required
placeholder=""
[satDatepicker]="picker"
[value]="dateRangeDisp"
(dateChange)="saveDate($event)"
>
<sat-datepicker #picker [rangeMode]="true"></sat-datepicker>
<sat-datepicker-toggle matSuffix [for]="picker"></sat-datepicker-toggle>
</mat-form-field>
and the function is :
saveDate(event: any) {
// look at how the date is emitted from save
console.log(event.target.value.begin);
//this.session.dateDebut = event.target.value.begin;
console.log(event.target.value.end);
// change in view
this.dateRangeDisp = event.target.value;
// save date range as string value for sending to db
// ... save to db
}
Upvotes: 2