I have a p-calendar element that is working correctly, but it has an annoying ui bug that allows the user to click to a year outside of the yearRange. They cannot selected a day in a year outside of the yearRange, as expected, but when they click on the year dropdown from a date outside of the yearRange, the yearRange in the dropdown is different. (e.g. if the original yearRange is 2016:2022 and the user selects Dec 2022 then clicks arrow to Jan 2023, when they click the year drop down they will now see 2022-2028)
<p-calendar
name="arrivedate"
[showIcon]="true"
[monthNavigator]="true"
[yearNavigator]="true"
yearRange="2016:2022"
formControlName="arrivedateCtrl"
dateFormat="yy/mm/dd"
placeholder="{{requireText}}"
readonlyInput="readonlyInput"
[locale]="calLanObj">
</p-calendar>
I'm trying to find a way to either not allow the user to click the arrows to a year outside the yearRange, or that when they click the year dropdown from a date outside of the range they will see the original yearRange in the dropdown.
Any ideas?
Thanks
There is no intended way to do this. So your options are:
Make a request to the devs in the github issues: https://github.com/primefaces/primeng/issues
Grab the source code from the github and modify it to what you want - you might even be able to merge it into the main product since primeng is open source: https://github.com/primefaces/primeng/tree/master/src/app/components/calendar
Use this janky hack:
We'll add event listeners for onYearChange and onMonthChange. Also, a template id so we can use ViewChild to do some questionable stuff.
<p-calendar
#calendar
[(ngModel)]="date"
[showIcon]="true"
[minDate]="minDate"
[maxDate]="maxDate"
(onYearChange)="checkYear($event)"
(onMonthChange)="checkYear($event)"
>
</p-calendar>
I've removed the deprecated property yearRange and use minDate and maxDate instead.
Then we'll add a function to check the year is within our bounds when the user changes it. We'll use @ViewChild to access all the functions and variables that we're not supposed to. Through trial and error, I found that calling the onModelTouched() function and then resetting our date value will update the date in the calendar.
import { Component, OnInit, ViewChild } from '@angular/core';
import { Calendar } from 'primeng/calendar';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss'],
})
export class TestComponent implements OnInit {
@ViewChild('calendar') calendar?: Calendar;
minDate = new Date(1451624400000); //Jan 1 2016
maxDate = new Date(1672462800000); //Dec 31 2022
date = new Date();
constructor() {}
ngOnInit(): void {}
checkYear(date: { month: number; year: number }) {
if (this.calendar) {
if (date.year < 2016) {
this.calendar.onModelTouched();
this.date = new Date(this.minDate);
}
if (date.year > 2022) {
this.calendar.onModelTouched();
this.date = new Date(this.maxDate);
}
}
}
}
If the user picks a date not within our range, we set it to the minimum or maximum value. We need to make sure to set the date using new Date() to ensure change detection will trigger every time.
Keep in mind this is using the component in an unintentional way, so there's no guarantee it won't break in future versions.
Stackblitz: https://stackblitz.com/edit/angular-ivy-emw3ge?file=src/app/test/test.component.ts