Flatpickr: Handling manual date input

Created on 29 Oct 2018  路  20Comments  路  Source: flatpickr/flatpickr



I have recently started using flatpickr. And, I am confused about how to tackle manual input. When I type a valid date manually, the change event is never called.

<input type="text" placeholder="Select Date.." class=date>
<div></div>
const fp = flatpickr(".date", {
  allowInput: true,
  onChange(_dates, currentDateString, _picker, _data){
    var divEl = document.createElement("div");    
    divEl.innerHTML = `[${new Date().toISOString()}] change: ${currentDateString}`;
    document.querySelector("div").appendChild(divEl);
  },
  parseDate(date){
    var divEl = document.createElement("div");    
    divEl.innerHTML = `[${new Date().toISOString()}] parsing ${date}`;
    document.querySelector("div").appendChild(divEl);
  }
});

Link to JSFiddle: https://jsfiddle.net/sayan751/ad7p3whv/

I am wondering if I need to attach a custom event listener on the input?

Your Environment

  • flatpickr version used: 4.5.2
  • Browser name and version:

    • Firefox 63.0

    • Chrome 69.0.3497.100

  • OS and version: Windows Server 2016

Most helpful comment

Another option is for the close event to use the manually changed input.

The following works for me (in the options object):

{
        altInput: true,
        allowInput: true,
        onClose(dates, currentdatestring, picker){
            picker.setDate(picker.altInput.value, true, picker.config.altFormat)
        }
}

All 20 comments

@aliniacb Though it works, it is very counterintuitive. When a user fill up a form, the user keys in the input in one field and press tab to move to next field. "enter" is usual for submitting a form. It is much better if the intuitive user interactions are supported.

I think flatpickr should expose an event for when users manually enter date input. In this case, perhaps the blur event would be a sensible option. That avoids the problems of firing for every key stroke and seems to capture the user intent for applications that do not require hitting enter for the form submission. Here is an example fiddle with a proposed onBlur hook:
https://jsfiddle.net/pjd62va5/

I can see the use case for updating the picker on blur if a new date was input. I will see what can be done to accomplish this, either via plugin or an option.

@aliniacb

It's like asking for a user password and submitting it with every keystroke.

... expect a date field is almost never a part of login form.

If you need a manual date input just use a regular input element and your done <input type="date">

It is actually about offering flexibility.

@chmln Thank you for the awesome control. It would be great if this supported out of the box. My workaround for this problem is also to leverage the blur event as suggested by @efx. Working fiddle: https://jsfiddle.net/sayan751/4xvhq23L/.

@Sayan751 Run in to this exact issue on an application where users fill in the date within the input field directly and the change didnt fired as expected.

What I did is manually fire the change whenever the hidden input field receives an update. Wait 10ms to make sure this updates next draw cycle such that the value is actually in there.

$(instance._input).bind('change', function () {
    // Time out to make sure we fire change on the next cycle
   setTimeout(function () {
       $date_picker.change();
    }, 10);
});

Hope this helps.

Flatpicker could implement the change fire by default whenever people set the allowInput option as it feels natural

@Montaldo Thank you for the workaround. In fact, I am using similar workaround based on "blur" event. However, it would be lot better if flatpickr supports this out-of-box :)

I have recently started using flatpickr. And, I am confused about how to tackle manual input. When I type a valid date manually, the change event is never called.

<input type="text" placeholder="Select Date.." class=date>
<div></div>
const fp = flatpickr(".date", {
  allowInput: true,
  onChange(_dates, currentDateString, _picker, _data){
    var divEl = document.createElement("div");    
    divEl.innerHTML = `[${new Date().toISOString()}] change: ${currentDateString}`;
    document.querySelector("div").appendChild(divEl);
  },
  parseDate(date){
    var divEl = document.createElement("div");    
    divEl.innerHTML = `[${new Date().toISOString()}] parsing ${date}`;
    document.querySelector("div").appendChild(divEl);
  }
});

Link to JSFiddle: https://jsfiddle.net/sayan751/ad7p3whv/

I am wondering if I need to attach a custom event listener on the input?

Your Environment

  • flatpickr version used: 4.5.2
  • Browser name and version:

    • Firefox 63.0
    • Chrome 69.0.3497.100
  • OS and version: Windows Server 2016

I also need that capability, because my users already get use to with jquery-ui datepicker which is have that flexibility, sadly jquery-ui not easy to use in vuejs environment. I hope @aliniacb and @chmln consider to accommodate this need. Thanks.

I've suggested my team to move away from this plugin. This is definitely a bug and it was not happening with v2.5.7.

This is how I think it could be fixed (in index.js)

  1. In bindEvents() function (around line 429), add this:
            if (self.config.allowInput)
                bind(self._input, "blur", onBlur);
  1. Add the blur handler (around line 1560)
        function onBlur(e) {
            var isInput = e.target === self._input;

            if (isInput) {
                self.setDate(self._input.value, true, e.target === self.altInput
                    ? self.config.altFormat
                    : self.config.dateFormat);
            }
        }

I just put them near the onKeyDown ones

Will this be fixed one day or not? If not, we'll have to stop using this plugin, as it's not working like an html form control should be working...

@dietergeerts we're all working on this in our spare time, so you may either wait patiently or submit a pull request yourself to speed things up.

I have got this working in a plugin (with support for partially entered dates) and hope to submit a PR soon

Another option is for the close event to use the manually changed input.

The following works for me (in the options object):

{
        altInput: true,
        allowInput: true,
        onClose(dates, currentdatestring, picker){
            picker.setDate(picker.altInput.value, true, picker.config.altFormat)
        }
}

The existing solutions felt a bit unnatural to me, so I ended up watching for a valid date, and when appropriate it either moves to the selected month, or changes the date immediately if a "full" date was entered and the cursor is at the end.

If there was a way to change just the calendar selection without modifying the edit box, that would make life even easier.

Here's an example (sorry about the jquery)

function dateInit(ctrlSelector, initialValue) {
    var dateInput = $(ctrlSelector);
    dateInput.val(initialValue);

    var fp = flatpickr(ctrlSelector, {
                            allowInput: true,
                            defaultDate: new Date(initialValue)
                        });

    dateInput.on('blur', function () {
        if (!isNaN(new Date(dateInput.val()))) {
            fp.setDate(dateInput.val());
        }
    }).on('keyup', function () {
        if (!isNaN(new Date(dateInput.val()))) {
            // if the cursor is at the end of the edit and we have a full sized date,
            // allow the date to immediately change, otherwise just move to the
            // correct month without actually changing it
            if (dateInput[0].selectionStart >= 10)
                fp.setDate(dateInput.val());
            else
                fp.jumpToDate(dateInput.val());
        }
    });
}

Test: https://jsfiddle.net/0kxswo6h/

@chmln thanks for your great job! Even so, I guess that is an important bug because it causes a bad UX.

Any updates on this one? This seems to be such a obvious behavior of any calendar widget, but it's very frustrating that it was not fixed for more than 3 years already :(

Current proposed solutions overview:
@efx's (https://jsfiddle.net/pjd62va5/) just doesn't work
@Sayan751's (https://jsfiddle.net/sayan751/4xvhq23L/) seems like working for handling internal data, but it doesn't update the calendar
@Montaldo's jQuery, but even when rewritten without it, the doesn't update the calendar, same as above
@smilingkite's is only for onClose which has nothing to do with initial issue

@jameskilts's (https://jsfiddle.net/0kxswo6h/) is the only one which is actually working somehow as expected.
Here is the fiddle reworked without jQuery https://jsfiddle.net/f5e37hxL/. However it still has issues with month/year changes (put cursor to month and change month number - calendar will jump to the month, but will not set the date) which is a bit annoying,

@matt17r Any idea when this hits npm?

@chmln @matt17r I tried linking the master branch. The changes seems to work. The current code in master branch also fixes https://github.com/flatpickr/flatpickr/issues/2019.

When are you guys considering a new release? I am seeing 37 commits made to master since last release (4.6.3 in Sep 2019) https://github.com/flatpickr/flatpickr/compare/v4.6.3...master, but no new version is released lately. I would say it is about time guys :)

In the meantime, here's a workaround I figured out that seems to update the flatpickr value correctly on input blur. The gist is that I grab the input used by flatpickr and add a blur event handler that will set the pickr date to the parsed input value. If altInput is true, flatpickr hides the original one and creates a replacement. This method can handle both cases.

function initPickr(el) {
  const pickr = flatpickr(el, {
    allowInput: true,
    dateFormat: "Z",
    altFormat: "Y-m-d H:i",
    altInput: true,
  });

  /* Add a blur event handler on input  used by flatpickr (created if `altInput` is `true`)
   * so that changing then leaving it (ie hit tab) will update the saved date value.
   * See https://github.com/flatpickr/flatpickr/issues/1551 */
  const { altInput, altFormat, dateFormat } = pickr.config;
  const input = altInput ? pickr.altInput : el;
  const format = altInput ? altFormat : dateFormat;

  function updateOnBlur(e) {
    pickr.setDate(e.target.value, true, format);
  }

  input.addEventListener("blur", updateOnBlur);

  return {
    destroy: () => {
      if (pickr) {
        input.removeEventListener("blur", updateOnBlur);
        pickr.destroy();
      }
    },
  };
}

Nevermind how I use the function (Svelte framework component initialization). I ensure to remove the listener and detroy the pickr on component unmount, but that is dependant on implementation.

I'm having the same problem but with time input rather than date input.

I use the following configuration:
datePickerConfig: { altInput: true, altFormat: "l, m/d/Y h:i K", allowInput: true, dateFormat: "Z", enableTime: true, },

It works if I change the time in the input area or via the up/down UI function, but if I type directly into the hours field, the new value does not get passed to the js with the input or blur event. See attached image for the hours field that I mean.
flatpickr

In this example, the time started as 7:24 am, but I changed it to 11 by typing. When I hit enter or click somewhere outside of flatpickr, the 7:24 am value remains unchanged when it should change to 11:24.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ibarral picture ibarral  路  3Comments

GlennMatthys picture GlennMatthys  路  3Comments

bedakb picture bedakb  路  3Comments

ankur-pandey7 picture ankur-pandey7  路  3Comments

zlepper picture zlepper  路  3Comments