I'm submitting a ...
[x] bug report => Search github for a similar issue or PR before submitting
[ ] feature request => Please check if request is not on the roadmap already https://github.com/primefaces/primeng/wiki/Roadmap
[ ] support request => Please do not submit support request here, instead see http://forum.primefaces.org/viewforum.php?f=35
Plunkr Case (Bug Reports)
https://stackblitz.com/edit/github-shrafb?file=src%2Fapp%2Fapp.component.html
Current behavior
cannot choose date after first pick
isMonthSelected doesn't check if value is Array
https://github.com/primefaces/primeng/blob/2eee286dd973211d2c58d288bb62af598cee331b/src/app/components/calendar/calendar.ts#L987
Angular version: 7.0
PrimeNG version: 7.0.4
Hi @user753 ,
I don麓t know if you still need it, but I found a temporary solution for month range, I took the original date range functions and I adapted them.
In your template:
<p-calendar [(ngModel)]="dateFilters" #monthPicker appendTo="body" selectionMode="range" [readonlyInput]="true" dateFormat="mm/yy" [showButtonBar]="true"></p-calendar>
In your component:
....
export class SomeComponent implements OnInit, AfterViewInit {
dateFilters: any;
@ViewChild('monthPicker') private _monthPicker: any;
readonly dateNow: Date = new Date(Date.now());
ngOnInit() { }
ngAfterViewInit(): void {
const currentYear = this.dateNow.getFullYear();
const currentMonth = this.dateNow.getMonth();
// I used it inside ngAfterViewInit, because I used it like a filter in TurboTable, but you can try it in ngOnInit
// Override the "isMonthSelected" function
this._monthPicker.isMonthSelected = (month) => this.isMonthSelectedHandler(month,
this.dateFilters, currentMonth, currentYear);
}
isMonthSelectedHandler(month: number, value: any, currentMonth: number, currentYear: number) {
const dateMeta = { month: currentMonth, year: currentYear};
if (value) {
if (value[1]) {
return this.monthEqualsHandler(value[0], month, currentYear) ||
this.monthEqualsHandler(value[1], month, currentYear) ||
this.isMonthBetweenHandler(value[0], value[1], dateMeta);
} else {
return this.monthEqualsHandler(value[0], month, currentYear);
}
} else {
return false;
}
}
monthEqualsHandler(value: any, month: number, currentYear: number) {
return value ? (value.getMonth() === month && value.getFullYear() === currentYear) : false;
}
isMonthBetweenHandler(start, end, dateMeta) {
let between: boolean = false;
if (start && end) {
const date: Date = new Date(dateMeta.year, dateMeta.month, 1);
return start.getMonth() <= date.getMonth() && start.getFullYear() <= date.getFullYear() &&
end.getMonth() >= date.getMonth() && end.getFullYear() >= date.getFullYear();
}
return between;
}
}
Hope it helps!
Regards.
Thank you, @jenniferarce , your solution is works, but has some design issues in default theme.
But I think this must be "out of the box" implementation of this function.
PrimeNG 8.0.0-RC1 still has this issue.
A little improved solution without design issues, working from any to any monthes, but still not working if switching through years.
Adapted for PrimeNG 8.0.0-RC1
HTML:
<p-calendar #dateFilter (onSelect)="onDatesRangeFilterSelected($event)" [(ngModel)]="datesRangeFilter" selectionMode="range" view="month" dateFormat="mm/yy" [readonlyInput]="true"></p-calendar>
TypeScript:
import { ViewChild } from '@angular/core';
@ViewChild('dateFilter', undefined) private dateFilter: any;
private datesRangeFilterCurrentSelectedValue: Date;
public datesRangeFilter: Date[];
ngAfterViewInit(): void {
this.dateFilter.isMonthSelected = (currentHandlingMonth) => this.isMonthSelectedHandler(currentHandlingMonth, this.datesRangeFilterCurrentSelectedValue, this.datesRangeFilter);
}
public onDatesRangeFilterSelected(selectedValue: Date) {
this.datesRangeFilterCurrentSelectedValue = selectedValue;
}
private isMonthSelectedHandler(currentHandlingMonth: number, selectedDate: Date, datesRange: Date[]) {
if (selectedDate) {
let selectedDateFullYear = selectedDate.getFullYear();
if (datesRange) {
if (datesRange[1]) {
return this.monthEqualsHandler(datesRange[0], currentHandlingMonth, selectedDateFullYear) ||
this.monthEqualsHandler(datesRange[1], currentHandlingMonth, selectedDateFullYear) ||
this.isMonthBetweenHandler(datesRange[0], datesRange[1], selectedDate, currentHandlingMonth);
} else {
return this.monthEqualsHandler(datesRange[0], currentHandlingMonth, selectedDateFullYear);
}
} else {
return false;
}
}
}
private monthEqualsHandler(value: Date, month: number, year: number) {
return value ? (value.getMonth() === month && value.getFullYear() === year) : false;
}
private isMonthBetweenHandler(start: Date, end: Date, selectedDate: Date, currentHandlingMonth: number) {
let between: boolean = false;
if (start && end) {
return start.getMonth() <= currentHandlingMonth && start.getFullYear() <= selectedDate.getFullYear() &&
end.getMonth() >= currentHandlingMonth && end.getFullYear() >= selectedDate.getFullYear();
}
return between;
}
Hi @PicOLinO , thanks for your solution, added to what you have done, I found the solution for the year change. I did some changes only on Typescript (I will copy your html code, just to keep it complete), because I realize that the 'ui-state-active' class is added according to isMonthSelect (you can check it here https://github.com/primefaces/primeng/blob/master/src/app/components/calendar/calendar.ts).
PrimeNG version: 7.1.0
HTML (your solution):
<p-calendar #dateFilter (onSelect)="onDatesRangeFilterSelected($event)" [(ngModel)]="datesRangeFilter" selectionMode="range" view="month" dateFormat="mm/yy" [readonlyInput]="true"></p-calendar>
Typescript:
import { ViewChild } from '@angular/core';
import { Calendar } from 'primeng/calendar';
@ViewChild('dateFilter', undefined) private dateFilter: Calendar;
private datesRangeFilterCurrentSelectedValue: Date;
public datesRangeFilter: Date[];
ngAfterViewInit(): void {
this.dateFilter.isMonthSelected = (currentHandlingMonth) =>
this.isMonthSelectedHandler(currentHandlingMonth, this.datesRangeFilterCurrentSelectedValue, this.dateFilters, this.dateFilter.currentYear);
}
public onDatesRangeFilterSelected(selectedValue: Date) {
this.datesRangeFilterCurrentSelectedValue = selectedValue;
}
private isMonthSelectedHandler(currentHandlingMonth: number, selectedDate: Date, datesRange: Date[], currentYear: number) {
if (selectedDate) {
if (datesRange) {
if (datesRange[1]) {
return this.monthEqualsHandler(datesRange[0], currentHandlingMonth, currentYear) ||
this.monthEqualsHandler(datesRange[1], currentHandlingMonth, currentYear) ||
this.isMonthBetweenHandler(datesRange[0], datesRange[1], currentHandlingMonth, currentYear);
} else {
return this.monthEqualsHandler(datesRange[0], currentHandlingMonth, currentYear);
}
} else {
return false;
}
}
}
private monthEqualsHandler(value: any, currentHandlingMonth: number, currentHandlingYear: number) {
return value ? (value.getMonth() === currentHandlingMonth && value.getFullYear() === currentHandlingYear) : false;
}
private isMonthBetweenHandler(start: Date, end: Date, currentHandlingMonth: number, currentHandlingYear: number) {
let between: boolean = false;
if (start && end) {
const startDate = new Date(start.getFullYear(), start.getMonth(), 1);
const endDate = new Date(end.getFullYear(), end.getMonth(), 1);
const currentDate = new Date(currentHandlingYear, currentHandlingMonth, 1);
// OPT 01
between = startDate.getTime() <= currentDate.getTime() &&
endDate.getTime() >= currentDate.getTime();
// OPT 02: If you don't want to manage days, this another option its working:
// between = (currentHandlingMonth > start.getMonth() && currentHandlingYear >= start.getFullYear()
// && ((currentHandlingMonth <= end.getMonth() && currentHandlingYear <= end.getFullYear())
// || currentHandlingMonth > end.getMonth() && currentHandlingYear < end.getFullYear()))
// || (currentHandlingMonth <= start.getMonth() && currentHandlingYear > start.getFullYear()
// && currentHandlingMonth < end.getMonth() && currentHandlingYear <= end.getFullYear());
}
return between;
}
Hope it helps!
Regards.
Thank you @jenniferarce , your solution works like a charm!