Last active
December 17, 2019 12:56
-
-
Save bartwttewaall/8b430a582709cac46d9455c49706c16f to your computer and use it in GitHub Desktop.
Angular Material mat-datepicker custom date validation and filter rules with extensible settings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const daysOffset = 1; // next day delivery | |
const deadlineTime = 17 * 3600; // 17:00 in seconds | |
const unavailableDays = [0, 1]; // sunday = 0, monday = 1 | |
const unavailableDates = [ | |
/* 2019 */ | |
{ dateString: '2019-01-01', name: 'Nieuwjaarsdag' }, | |
{ dateString: '2019-04-01', name: '1e paasdag' }, | |
{ dateString: '2019-04-22', name: '2e paasdag' }, | |
{ dateString: '2019-04-27', name: 'Koningsdag' }, | |
{ dateString: '2019-05-30', name: 'Hemelvaartsdag' }, | |
{ dateString: '2019-06-09', name: '1e pinksterdag' }, | |
{ dateString: '2019-06-10', name: '2e pinksterdag' }, | |
{ dateString: '2019-12-25', name: '1e kerstdag' }, | |
{ dateString: '2019-12-26', name: '2e kerstdag' }, | |
/* 2020 */ | |
{ dateString: '2020-01-01', name: 'Nieuwjaarsdag' }, | |
{ dateString: '2020-04-10', name: 'Goede vrijdag' }, | |
{ dateString: '2020-04-12', name: '1e paasdag' }, | |
{ dateString: '2020-04-13', name: '2e paasdag' }, | |
{ dateString: '2020-04-27', name: 'Koningsdag' }, | |
{ dateString: '2020-05-05', name: 'Bevrijdingsdag' }, | |
{ dateString: '2020-05-21', name: 'Hemelvaartsdag' }, | |
{ dateString: '2020-05-31', name: '1e pinksterdag' }, | |
{ dateString: '2020-06-01', name: '2e pinksterdag' }, | |
{ dateString: '2020-12-25', name: '1e kerstdag' }, | |
{ dateString: '2020-12-26', name: '2e kerstdag' } | |
]; | |
export function getDateOffset(): number { | |
const beforeDeadline = getCurrentTimeInSeconds() < deadlineTime; | |
return daysOffset + (beforeDeadline ? 0 : 1); | |
} | |
export function getValidNextDate() { | |
return dateAddDays(new Date(), getDateOffset()); | |
} | |
export function getFirstAvailableDate(startDate: Date): Date { | |
let date = new Date(startDate); | |
let isValidDate = validateShippingDate(date); | |
let numTries = 0; | |
while (!isValidDate && ++numTries < 365) { | |
// try the next day | |
date = dateAddDays(date, 1); | |
isValidDate = validateShippingDate(date); | |
} | |
return date; | |
} | |
export const validateShippingDate = (date: Date) => { | |
if (unavailableDays.includes(date.getDay())) return false; | |
const dateString = getDateString(date); | |
return ( | |
unavailableDates.filter(entry => { | |
return entry.dateString === dateString; | |
}).length === 0 | |
); | |
} | |
// ---- utils ---- | |
export function dateAddDays(date: Date, offset: number = 1): Date { | |
const clone = new Date(date); | |
clone.setDate(clone.getDate() + offset); | |
return clone; | |
} | |
export function getCurrentTimeInSeconds(): number { | |
const now = new Date(); | |
return now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds(); | |
} | |
// DO NOT use date.toISOString().slice(0, 10). It doesn't keep the timezone in mind | |
export function getDateString(date: Date) { | |
return [date.getFullYear(), date.getMonth() + 1, date.getDate()] | |
.map(entry => (entry.toString().length === 1 ? '0' + entry : entry)) | |
.join('-'); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<mat-card class="shipping-card"> | |
<mat-card-header> | |
<mat-card-title>Shipping</mat-card-title> | |
</mat-card-header> | |
<mat-card-content> | |
<form class="form-vertical" [formGroup]="form"> | |
<p>When you order before 17:00 hours we'll be able ship this very evening and you can expect a next day delivery.</p> | |
<div class="form-group"> | |
<label>Bezorgdag</label> | |
<mat-form-field appearance="outline"> | |
<input | |
matInput | |
formControlName="shippingDate" | |
[matDatepickerFilter]="shippingDateFilter" | |
[matDatepicker]="picker" | |
[min]="shippingDateMin" | |
[max]="shippingDateMax" | |
(inputChange)="onShippingDateChanged($event)" | |
(dateChange)="onShippingDateChanged($event)" | |
/> | |
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> | |
<mat-datepicker #picker></mat-datepicker> | |
</mat-form-field> | |
</div> | |
</form> | |
</mat-card-content> | |
</mat-card> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Component, OnInit, Input } from '@angular/core'; | |
import { MatDatepickerInputEvent } from '@angular/material'; | |
import { FormGroup, FormBuilder, Validators } from '@angular/forms'; | |
import { validateShippingDate, getFirstAvailableDate, getValidNextDate, dateAddDays } from './shipping-date.util'; | |
@Component({ | |
selector: 'page-shipping', | |
templateUrl: './shipping.component.html', | |
styleUrls: ['./shipping.component.scss'] | |
}) | |
export class PageShippingComponent implements OnInit { | |
@Input() | |
selectedDate: Date; | |
shippingDateMin: Date; | |
shippingDateMax: Date; | |
shippingDateFilter = validateShippingDate; | |
form: FormGroup = this.fb.group({ | |
shippingDate: new FormControl('', Validators.required) | |
}); | |
constructor(private fb: FormBuilder) {} | |
ngOnInit() { | |
this.shippingDateMin = getFirstAvailableDate(getValidNextDate()); | |
this.shippingDateMax = dateAddDays(this.shippingDateMin, 180); | |
const useSelectedDate = this.selectedDate && this.selectedDate > this.shippingDateMin; | |
const shippingDate = useSelectedDate ? getFirstAvailableDate(this.selectedDate) : this.shippingDateMin; | |
this.form.get('shippingDate').setValue(shippingDate); | |
} | |
onShippingDateChanged(evt: MatDatepickerInputEvent<Date>) { | |
console.log(evt.value); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment