I have a form_for
form. Some of my fields are for selecting dates, which I'm using flatpickr for. I'm having trouble making the field required using form validation on the client side.
I have the following basic flatpickr code in application.js
:
flatpickr("[data-behavior='flatpickr']", {
altInput: true,
altFormat: "F j, Y",
dateFormat: "Y-m-d"
});
In my view, I've tried making a field like this (with many variations):
<%= f.text_field :attribute_name,
{ label: "Description of attribute", data: { behavior: "flatpickr" }, required: true } %>
which produces this HTML:
<label class="required" for="model_name_attribute_name">Description of attribute</label>
<input data-behavior="flatpickr" required="required" class="form-control flatpickr-input" type="hidden" name="model_name[attribute_name]" id="model_name_attribute_name">
<input class="form-control form-control input" placeholder="" required="" tabindex="0" type="text" readonly="readonly">
Everything works, except I can't figure out how to make the field required. Flatpickr creates a hidden field that holds the actual date value selected in their javascript pop-up and then it displays it using whatever format you like in the visible field which is readonly
because it's set by flatpickr. It seems like my attempts to make the field "required" have made the label have the "required" class and made the hidden field "required" while leaving my visible field with required=''
which is not sufficient enough to halt submission when nothing has been selected and the field is empty. I have a server-side validation catching it but I want to find a way for the client-side validation to work also.
Apparently it's a known bug in flatpickr which has not been fixed yet, at least as of writing this, but it looks like it's been around several years. As a workaround, I ended up successfully solving this by adding allowInput: true
in my flatpickr config like in the following example:
flatpickr("[data-behavior='flatpickr']", {
allowInput: true,
altInput: true,
altFormat: "F j, Y",
dateFormat: "Y-m-d"
});
I then wanted to automatically select all the text in the field when the user focuses (through clicking or the tab button) on flatpickr fields and inspired by this, I settled on this solution using jQuery:
$("[data-behavior='flatpickr']").next().focus(function() {
$(this).on("click.a keyup.a", function(e){
$(this).off("click.a keyup.a").select();
});
});
The key difference from the original code that was necessary to get it working was the .next()
. As I noted earlier, flatpickr creates a hidden field to store the date selected with the pop-up picker and technically it's that hidden field which has the id
and the data-behavior
attribute. So with next()
, we are listening to the visible field, which is the next element.
Many alternative approaches are discussed on the flatpickr GitHub issue page for those wanting a different approach, depending on your needs.