DEV Community

Cover image for Rails Stimulus Flatpickr Controller
Andrew Cetinic for PeopleForce

Posted on

Rails Stimulus Flatpickr Controller

At peopleforce.io we try to stick to as close as possible to the recommended Rails technologies available. This includes Stimulus JS to help separate common behaviours into their own controllers across views.

For our data pickers we decided to use flatpickr which we found to be the most flexible datepicker available in terms of configuration options and features.

Below is our implementation of how we extracted Flatpickr to be used across all our Rails forms with support of different date formats and I18n.

.erb

   <%= f.date_picker_field :date_of_birth %>

application_form_builder.rb

class ApplicationFormBuilder < ActionView::Helpers::FormBuilder
  def date_picker_field(method, options = {})
    options[:class] = options[:class] || "form-control "
    options[:placeholder] = Current.user.settings.date_format
    options[:data] = {"target" => "date-picker.picker"}
    options[:autocomplete] = "off"
    options[:required] = options[:required] if options[:required]

    inner_tags = @template.text_field_tag(method, (options.has_key?(:value) ? options[:value] : object.send(method)), options)
    inner_tags << @template.hidden_field(@object_name, method, {
        value: (options.has_key?(:value) ? options[:value] : object.send(method).try(:strftime, "%F")),
        data: {target: "date-picker.input"}
    })

    return @template.content_tag(:div, inner_tags, {data: {controller: "date-picker"}})
  end
end

date_picker_controller.js

// LOCALE - global variable for preferred user language. eg. "en", "es", "ru"
// DATE_FORMAT - global variable for user preferred date format. eg. 'DD-MM-YYYY'

import {Controller} from "stimulus"
import flatpickr from "flatpickr";
import "flatpickr/dist/l10n/ru.js"
import "flatpickr/dist/l10n/uk.js"
import moment from "moment";

flatpickr.l10ns.en.firstDayOfWeek = 1;

export default class extends Controller {
    static targets = ["input", "picker"]

    initialize() {
        let controller = this;

        var DATE_FORMATS = {
            "YYYY-MM-DD": "Y-m-d",
            "DD.MM.YYYY": "d.m.Y",
            "DD/MM/YYYY": "d/m/Y",
            "MM.DD.YYYY": "m.d.Y",
            "MM/DD/YYYY": "m/d/Y"
        }

        let flatPicker = flatpickr(this.pickerTarget, {
            "dateFormat": DATE_FORMATS[DATE_FORMAT],
            "locale": LOCALE,
            allowInput: true,
            onClose: (selectedDates, dateStr, instance) => {
                if (dateStr == "") {
                    controller.inputTarget.value = "";
                    instance.clear();
                } else {
                    let d = instance.parseDate(controller.pickerTarget.value, DATE_FORMATS[DATE_FORMAT]);
                    flatPicker.setDate(d);
                    controller.inputTarget.value = moment(d).format("YYYY-MM-DD");
                    controller.pickerTarget.value = instance.formatDate(d, DATE_FORMATS[DATE_FORMAT]);
                }
            }
        });
    }
}

Top comments (1)

Collapse
 
adrienpoly profile image
Adrien Poly

Hey

you might want to check github.com/adrienpoly/stimulus-fla... and a detailed article

There is a built in strftime format converter to Flatpickr Date/Time model. This can avoid loading the costly moment library

happy Stimulus