Primeng: P-Calendar fires onBlur event upon clicking a date in the calendar

Created on 8 Mar 2019  路  4Comments  路  Source: primefaces/primeng

I'm submitting a ... (check one with "x")

[ 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

Current behavior
We have a p-calendar with an onBlur event. When we expand the calendar, and click a date to select it, the onBlur event is getting fired. Afterwards, the p-calendar field is re-focused. Then, once the field is actually blurred by the user, onBlur fires again.

Expected behavior
There is already a onSelect event which is meant to fire when the user selects a date through the calendar. Also, the field remains focused after the user selects a date. For these two reasons, it does not make sense for onBlur to fire upon clicking a date in the calendar. onBlur should only fire when the field is actually blurred by the user.

Minimal reproduction of the problem with instructions
Create a p-calendar with onBlur event.

  • Angular version: 5.X
    Angular 5.2.1

  • PrimeNG version: 5.X
    PrimeNg 5.2.5

  • Browser:
    Chrome

LTS-FIXED-8.1.4 enhancement

Most helpful comment

Same here! @cagataycivici some news?

For us the issue appears when use minDate.

If you remove it from the following example everything works, if it's present you must click two times in the date to select it, after blur the selectDate function is not called the first time.

<p-calendar
    #followUpCalendar
    [dateFormat]="calendarLocalizationSettings.dateFormat"
    [disabledDays]="[0,6]"
    [locale]="calendarLocalizationSettings"
    [minDate]="followUpRange.min" <----------------------------------
    [monthNavigator]="true"
    [readonlyInput]="true"
    [showButtonBar]="true"
    [showIcon]="true"
    [yearNavigator]="true"
    [yearRange]="followUpYearRange"
    (onClearClick)="onDeleteFollowUpDate()"
    (onSelect)="onSelectFollowUpDate($event)">
get followUpRange(): { min?: Date, max?: Date } {
    return {
      min: addDays(new Date(), 1)
    };
  }

private setCalendarLocalizationSettings(): void {
    this.calendarLocalizationSettings = {
      firstDayOfWeek: getLocaleFirstDayOfWeek(this.translateService.currentLang),
      dayNames: getLocaleDayNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Wide),
      dayNamesMin: getLocaleDayNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Abbreviated),
      dayNamesShort: getLocaleDayNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Short),
      monthNames: getLocaleMonthNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Wide),
      monthNamesShort: getLocaleMonthNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Short),
      today: this.translateService.instant('TODAY'),
      clear: this.translateService.instant('ACTION.CLEAR'),
      dateFormat: getLocaleDateFormat(this.translateService.currentLang, FormatWidth.Short)
    };
  }

get followUpYearRange(): string {
    const currentYear = new Date().getFullYear();
    const nextYear = addYears(new Date(), 1)
      .getFullYear();

    return `${currentYear}:${nextYear}`;
  }

PD: addYears and addDays functions returns a Date.

All 4 comments

Having the same problem with primeng 7.1.2 and angular 7.2.14.
This seems quite critical for me as I would like to set the "default" date if user has given incorrect date and leaves the input, but it turns out that I override user's input when he selects a date in calendar.

Please find steps to reproduce below:

  • Put cursor in calendar input and erase the date
  • Select any date in calendar
  • (onBlur) event is fired and selected date in calendar gets overwritten with "default" date

Here are some results of a short investigation:
The <p-calendar> template contains an input that has (blur)="onInputBlur($event)" callback attached to it that leads to onBlur event being triggered if user leaves input to click smth in calendar dropdown (datepicker). The onInputBlur function code is following:

    onInputBlur(event: Event) {
        this.focus = false;
        this.onBlur.emit(event);
        if (!this.keepInvalid) {
            this.updateInputfield();
        }
        this.onModelTouched();
    }

However there is another function that might help us solve this problem in case of "input+datepicker" configuration - bindDocumentClickListener(). It basically watches every click use makes while datepicker dropdown is open and closes mentioned dropdown if click was made outside of component template (including datepicker). The code of the function is following:

    bindDocumentClickListener() {
        if (!this.documentClickListener) {
            this.documentClickListener = this.renderer.listen('document', 'click', (event) => {
                if (this.isOutsideClicked(event) && this.overlayVisible) {
                    this.hideOverlay();
                }

                this.cd.detectChanges();
            });
        }
    }

So I would propose to add another @Output called onClickOutside() that will be thrown after this.hideOverlay(); function is called in bindDocumentClickListener().

Same here! @cagataycivici some news?

For us the issue appears when use minDate.

If you remove it from the following example everything works, if it's present you must click two times in the date to select it, after blur the selectDate function is not called the first time.

<p-calendar
    #followUpCalendar
    [dateFormat]="calendarLocalizationSettings.dateFormat"
    [disabledDays]="[0,6]"
    [locale]="calendarLocalizationSettings"
    [minDate]="followUpRange.min" <----------------------------------
    [monthNavigator]="true"
    [readonlyInput]="true"
    [showButtonBar]="true"
    [showIcon]="true"
    [yearNavigator]="true"
    [yearRange]="followUpYearRange"
    (onClearClick)="onDeleteFollowUpDate()"
    (onSelect)="onSelectFollowUpDate($event)">
get followUpRange(): { min?: Date, max?: Date } {
    return {
      min: addDays(new Date(), 1)
    };
  }

private setCalendarLocalizationSettings(): void {
    this.calendarLocalizationSettings = {
      firstDayOfWeek: getLocaleFirstDayOfWeek(this.translateService.currentLang),
      dayNames: getLocaleDayNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Wide),
      dayNamesMin: getLocaleDayNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Abbreviated),
      dayNamesShort: getLocaleDayNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Short),
      monthNames: getLocaleMonthNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Wide),
      monthNamesShort: getLocaleMonthNames(this.translateService.currentLang, FormStyle.Standalone, TranslationWidth.Short),
      today: this.translateService.instant('TODAY'),
      clear: this.translateService.instant('ACTION.CLEAR'),
      dateFormat: getLocaleDateFormat(this.translateService.currentLang, FormatWidth.Short)
    };
  }

get followUpYearRange(): string {
    const currentYear = new Date().getFullYear();
    const nextYear = addYears(new Date(), 1)
      .getFullYear();

    return `${currentYear}:${nextYear}`;
  }

PD: addYears and addDays functions returns a Date.

@cagataycivici @yigitfindikli some news here?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KannanMuruganmony picture KannanMuruganmony  路  3Comments

jisqaqov picture jisqaqov  路  3Comments

markgoho picture markgoho  路  3Comments

jisqaqov picture jisqaqov  路  3Comments

watalberto picture watalberto  路  3Comments