开发者

How do i write a cleaner date picker input for SimpleForm

开发者 https://www.devze.com 2023-02-11 09:38 出处:网络
I love the simple_form gem for rails but i dont like this line of code: <%= f.input :deadline, :as => :string, :input_html => { :class => \'date_picker\' } %>

I love the simple_form gem for rails but i dont like this line of code:

<%= f.input :deadline, :as => :string, :input_html => { :class => 'date_picker' } %>

I would like to write:

<%= f.input :deadline开发者_开发技巧, :as => :date_picker %>

or even over write the :date / :datetime matchers completely.

But i dont really want to write a whole custom_simple_form

I think it must be possible...

Please help thanks


The answers here seem a bit out of date if you are using simple_form 2.0.

I've been fighting with this for a while and was able to concoct this; it uses inheritance (notice that it is a subclass of StringInput, not Base), supports i18n and adds the datepicker css class in a more clean way, IMHO.

# app/inputs/date_picker_input.rb

class DatePickerInput < SimpleForm::Inputs::StringInput 
  def input                    
    value = input_html_options[:value]
    value ||= object.send(attribute_name) if object.respond_to? attribute_name
    input_html_options[:value] ||= I18n.localize(value) if value.present?
    input_html_classes << "datepicker"

    super # leave StringInput do the real rendering
  end
end

The usage is like above:

<%= f.input :deadline, :as => :date_picker %>

And the javascript remains the same:

$("input.date_picker").datepicker();


You have to define a new DatePickerInput class.

module SimpleForm
  module Inputs
    class DatePickerInput < Base
      def input
        @builder.text_field(attribute_name,input_html_options)
      end    
    end
  end
end

And you can now write

<%= f.input :deadline, :as => :date_picker %>

Off course you also need

 $("input.date_picker").datepicker();

in application.js

This is very useful to localize dates. Look at this:

module SimpleForm
  module Inputs
    class DatePickerInput < Base
      def input
        @builder.text_field(attribute_name, input_html_options.merge(datepicker_options(object.send(attribute_name))))
      end

      def datepicker_options(value = nil)
        datepicker_options = {:value => value.nil?? nil : I18n.localize(value)}
      end

    end
  end
end

You have now a localized date in the text field!

Update: a cleaner way to do the same

module SimpleForm
  module Inputs
    class DatePickerInput < SimpleForm::Inputs::StringInput
      def input_html_options
        value = object.send(attribute_name)
        options = {
          value: value.nil?? nil : I18n.localize(value),
          data: { behaviour: 'datepicker' }  # for example
        }
        # add all html option you need...
        super.merge options
      end
    end
  end
end

Inherit from SimpleForm::Inputs::StringInput (as @kikito said) and add some html options. If you need also a specific class you can add something like

def input_html_classes
  super.push('date_picker')
end


Based on @kikito's answer, I did this to get a native datepicker (i.e. no special JS classes).

config/initializers/simple_form_datepicker.rb

class SimpleForm::Inputs::DatepickerInput < SimpleForm::Inputs::StringInput 
  def input                    
    input_html_options[:type] = "date"
    super
  end
end

Then used it like:

f.input :paid_on, as: :datepicker

Note that if you also have a simple_form_bootstrap3.rb initializer or similar, like we did, you should:

  1. add DatepickerInput to its list of inputs
  2. make sure the simple_form_bootstrap3.rb (or similar) initializer loads after simple_form_datepicker.rb, so that the DatepickerInput class is available. Do that by e.g. renaming the datepicker initializer to simple_form_0_datepicker.rb.


An other option could also be to overwrite the default DateTimeInput helper, here's an example to be placed in app/inputs/date_time_input.rb

class DateTimeInput < SimpleForm::Inputs::DateTimeInput
  def input
    add_autocomplete!
    @builder.text_field(attribute_name, input_html_options.merge(datetime_options(object.send(attribute_name))))
  end

  def label_target
    attribute_name
  end

  private

    def datetime_options(value = nil)
      return {} if value.nil?

      current_locale = I18n.locale
      I18n.locale = :en

      result = []
      result.push(I18n.localize(value, { :format => "%a %d %b %Y" })) if input_type =~ /date/
      if input_type =~ /time/
        hours_format = options[:"24hours"] ? "%H:%M" : "%I:%M %p"
        result.push(I18n.localize(value, { :format => hours_format }))
      end

      I18n.locale = current_locale

      { :value => result.join(', ').html_safe }
    end

    def has_required?
      options[:required]
    end

    def add_autocomplete!
      input_html_options[:autocomplete] ||= 'off'
    end
end

Please notice than while using this method makes it a drop feature for your forms, it might also break with future versions of simple_form.

Notice about localized dates: As far as I know Ruby interprets dates following only a few formats, you might want to be careful before localizing them and make sure Ruby can handle them. An attempt to better localization support on the Ruby Date parsing as been started at https://github.com/ZenCocoon/I18n-date-parser, yet, this is not working.


In new formtastic previews answers doesn't work. See http://justinfrench.com/notebook/formtastic-2-preview-custom-inputs Here is a simple working example (save to app/inputs/date_picker_input.rb):

class DatePickerInput < Formtastic::Inputs::StringInput
  def input_html_options
    {
      :class => 'date_picker',
    }.merge(super).merge({
      :size => '11'
    })
  end
end

Create a file app/assets/javascripts/date_picker.js with content:

$(function() {
  $("input#.date_picker").datepicker();
});

You also need to load jquery-ui. To do so, insert to app/assets/javascripts/application.js line:

//= require jquery-ui

or simply use CDN eg:

<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js" %>
<%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.1/jquery-ui.min.js" %>

Stylesheets for jquery-ui coul be inclded http://babinho.net/2011/10/rails-3-1-jquery-ui/ or from CDN:

<%= stylesheet_link_tag    "application", "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.8/themes/ui-lightness/jquery-ui.css" %>
0

精彩评论

暂无评论...
验证码 换一张
取 消