DEV Community

loading...
Cover image for Rails Stimulus Flatpickr Controller
PeopleForce

Rails Stimulus Flatpickr Controller

Andrew Cetinic
Founder of peopleforce.io
・2 min read

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]);
                }
            }
        });
    }
}

Discussion (0)

Forem Open with the Forem app