Primeng: Calendar minDate and maxDate bindings don't work

Created on 28 Oct 2016  Â·  14Comments  Â·  Source: primefaces/primeng

Hey everybody,

I have in my form a starting date and a ending date. I set the starting date as the minDate of the ending date field and the ending date as the maxDate of the starting date.

But the binding doesn't work well : for the ending date I could select a date before the starting date and for the starting date I could select a date that is after the ending date.

It seems that both minDate and maxDate are not updated if and only if I changed the month and come back to actual month.

I built a custom calendar component that includes all primeng calendar options.

my-calendar.component.html:
<div [formGroup]="calendarForm"> <p-calendar #pcalendar [(ngModel)]="date" formControlName="calendar" [minDate]="minDate" [maxDate]="maxDate" [locale]="fr" dateFormat="dd/mm/yy" [monthNavigator]="true" [yearNavigator]="true" yearRange="2000:2030" inputStyleClass="form-control input-sm" (onBlur)="onBlur($event)" (onSelect)="onSelect($event)"> </p-calendar> </div>

my-calendar.component:
`import { Component, Input, Output, EventEmitter, OnInit, ViewChild } from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { Calendar } from 'primeng/primeng';
import * as moment from 'moment';

@Component({
selector: 'sig-calendar',
templateUrl: './my-calendar.component.html'
})

export class MyCalendarComponent implements OnInit {
@ViewChild('pcalendar') pcalendar: Calendar;
private fr: any;

@Output() minDateChange: EventEmitter<Date> = new EventEmitter<Date>();
@Output() maxDateChange: EventEmitter<Date> = new EventEmitter<Date>();
@Output() dateChange: EventEmitter<Date> = new EventEmitter<Date>();
@Input() date: Date = null;
@Input() minDate: Date = null;
@Input() maxDate: Date = null;

@Input() controlChange: EventEmitter<FormControl> = new EventEmitter<FormControl>();
@Input() control: FormControl = null;
calendarForm: FormGroup;

constructor() { }

ngOnInit() {
    this.fr = {
        firstDay: 1,
        monthNames: [
            'janvier', 'février', 'mars',
            'avril', 'mai', 'juin',
            'juillet', 'août', 'septembre',
            'octobre', 'novembre', 'décembre'
        ],
        monthNamesShort: ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin', 
                        'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.'],
        dayNames: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'],
        dayNamesShort: ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'],
        dayNamesMin: ['D', 'L', 'M', 'M', 'J', 'V', 'S']
    };

    this.calendarForm = new FormGroup({});
    if (this.control) {
        this.calendarForm.addControl('calendar', this.control);
    }
}

emitChanges() {
    if (this.minDate) {
        this.minDateChange.emit(this.minDate);
    }
    if (this.maxDate) {
        this.maxDateChange.emit(this.maxDate);
    }
    this.dateChange.emit(this.date);
    this.emitControlChanges();
}

emitControlChanges() {
    if (this.control) {
        this.control.setValue(this.date);
        this.control.markAsDirty();
        this.control.markAsTouched();
        if (this.date === null) {
            this.control.setErrors({key: 'required'}, {emitEvent: true});
        }
        this.control.updateValueAndValidity();
        this.controlChange.emit(this.control);
    }
}

onBlur(event) {
    let newDate: Date = this.strToDate(event.target.value);
    this.date = newDate;
    let newValue: string = this.dateToStr(newDate);
    event.target.value = newValue;
    this.emitChanges();
}

onSelect(event) {
    let newDate = this.strToDate(event);
    this.date = newDate;
    this.emitChanges();
}

strToDate(newDateString: string): Date {
    if (newDateString) {
        let mom: moment.Moment = moment(newDateString, 'DD/MM/YYYY');
        if (mom.isValid()) {
            return mom.toDate();
        }
    }
    return null;
}

dateToStr(newDate: Date, format?: string): string {
    if (newDate && moment(newDate).isValid()) {
        if (format) {
            return moment(newDate).format(format);
        }
        return moment(newDate).format('DD/MM/YYYY');
    }
    // date vide ou incorrecte
    return '';
}

}`

My form :
<form class="form-group"> <label class="col-sm-2 control-label"> Starting date </label> <div class="col-sm-2"> <sig-calendar #calendarStart [(date)]="filter.startDate" [(control)]="startDateControl" [(maxDate)]="filter.endDate"></sig-calendar> </div> <label class="col-sm-1 control-label"> Ending date </label> <div class="col-sm-2"> <sig-calendar #calendarEnd [(date)]="filter.endDate" [(control)]="endDateControl" [(minDate)]="filter.startDate"></sig-calendar> </div> </form>

I am looking forward for suggestions about this issue.

Thanks in advance,

defect

Most helpful comment

For me in 5.0.2 is still reproduced.
Reproduce - https://drive.google.com/file/d/1PoWogpz_u2v6NYeGKkisqTIO4Rfr9FCS/view
How to fix:

  1. template:
<p-calendar #fromCalendar
    <!--...-->
    (onFocus)="updateCalendarUI(fromCalendar)">
</p-calendar>
  1. component:
import { Calendar } from 'primeng/primeng';
//...
updateCalendarUI(calendar: Calendar) {
    calendar.updateUI();
}

It's pity because it's not described in official docs =(

All 14 comments

I have the same issue. I have a form that has a start date and end date. I am trying to use minDate and maxDate to make sure start date can't be chosen before end date, and vice versa.

But when I set the date in the start date field, and then open the calendar for the end date field, all the values for the current month are still available. If I page back to the previous month the dates are disabled as expected, and paging back to the current month will now show dates disabled properly.

I have the same issue #1114

I fixed it with layout refresh, like:

export class MyCalendarComponent implements OnInit {
active = true;
...

onSelect(event) {
...
this.active = false;
setTimeout(() => this.active = true, 0);
}

Thanks @sashabolcina — I'm using that workaround for now too. Hope this gets fixed soon, because the layout refresh causes a blink!

I have this same issue. Odd that there's no acknowledgement from the devs about this. Still see this in RC 7

I just started using primeng yesterday (actually only for the calendar!) and I'm finding this issue - minDate bindings aren't working and I'm not invested enough to play around with OnInit hacks to get it working...

It's been a month and they've still not fixed this.. Really.

@chrillewoodz submit a PR...?

Is it fixed

For me in 5.0.2 is still reproduced.
Reproduce - https://drive.google.com/file/d/1PoWogpz_u2v6NYeGKkisqTIO4Rfr9FCS/view
How to fix:

  1. template:
<p-calendar #fromCalendar
    <!--...-->
    (onFocus)="updateCalendarUI(fromCalendar)">
</p-calendar>
  1. component:
import { Calendar } from 'primeng/primeng';
//...
updateCalendarUI(calendar: Calendar) {
    calendar.updateUI();
}

It's pity because it's not described in official docs =(

@qetr1ck-op
When trying

import { Calendar } from 'primeng/primeng';
//...component stuff

updateCalendar(calendar: Calendar){
  calendar.updateUI();
}

I get the following

TypeError: calendar.updateUI is not a function at

It kinda seems like the Calendar interface and what's actually rendered are different.

@jbreitenbach Hmm.
What is then the type of yours calendar parameter in method?
Did you declare a template variable on <p-calendar #myCalendar ... ?
Did you pass it into onFocus handler?

@qetr1ck-op Thank you for your reply.

Yes,
The param is typed as :Calendar, there is a template variable and the handler call is being made correctly.
Your example was followed exactly as described (although with a few more calendar properties), However, that's not going to change the overall api of the component and/or the methods able to be called.

I've even tried grabbing the p-calendar as a ViewChild() with no luck calling the .updateUI() method along with a few other methods declared within the Calendar interface.

I'm not sure if your using a different version of primeng than I or if there is some other issue.
It just seems that what the typing for :Calendar is describing isn't actually what is being rendered.

@jbreitenbach
Right. Could you show the result console.log of the #templateVar?
Public method which you're interested - https://github.com/primefaces/primeng/blob/master/src/app/components/calendar/calendar.ts#L1236

Was this page helpful?
0 / 5 - 0 ratings