-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Custom inputs examples
In order to get an input with localized week days:
# app/inputs/wday_input.rb
class WdayInput < SimpleForm::Inputs::Base
def input(wrapper_options)
@builder.select(attribute_name, I18n.t(:"date.day_names").each_with_index.to_a)
end
end
Then, use it in your form:
<%= timetable.input :wday, :as => :wday %>
Date Time Picker for Twitter Bootstrap 3 using the DateTimePicker JS Library
## app/inputs/date_time_picker_input.rb
class DateTimePickerInput < SimpleForm::Inputs::Base
def input(wrapper_options)
template.content_tag(:div, class: 'input-group date form_datetime') do
template.concat @builder.text_field(attribute_name, input_html_options)
template.concat span_remove
template.concat span_table
end
end
def input_html_options
super.merge({class: 'form-control', readonly: true})
end
def span_remove
template.content_tag(:span, class: 'input-group-addon') do
template.concat icon_remove
end
end
def span_table
template.content_tag(:span, class: 'input-group-addon') do
template.concat icon_table
end
end
def icon_remove
"<i class='glyphicon glyphicon-remove'></i>".html_safe
end
def icon_table
"<i class='glyphicon glyphicon-th'></i>".html_safe
end
end
To use add this to an appropriate coffee script file
$(document).ready ->
$('.form_datetime').datetimepicker({
autoclose: true,
todayBtn: true,
pickerPosition: "bottom-left",
format: 'mm-dd-yyyy hh:ii'
});
call on simple form input with
f.input :my_date, as: :date_time_picker
Input that submits an array of strings. Starts with one blank input and clones it when the Add button is clicked. Remove button is hidden with JS if it is the only entry.
# app/inputs/array_input.rb
class ArrayInput < SimpleForm::Inputs::StringInput
def input(wrapper_options = nil)
input_html_options[:type] ||= input_type
existing_values = object.public_send(attribute_name)
existing_values.push(nil) if existing_values.blank?
template.content_tag(:div, class: 'text-array', id: "#{object_name}_#{attribute_name}") do
Array(existing_values).map do |array_el|
template.concat build_row(array_el)
end
template.concat add_button
end
end
def input_type
:text
end
private
def build_row(val)
template.content_tag(:div, class: 'text-array__row') do
template.concat @builder.text_field(nil,
input_html_options.merge(value: val, name: "#{object_name}[#{attribute_name}][]"))
template.concat remove_button
end
end
def add_button
'<button class="text-array__add" href="#">Add</button>'.html_safe
end
def remove_button
'<button class="text-array__remove" href="#">Remove</button>'.html_safe
end
end
Add coffeescript for the buttons:
$(document).ready ->
addRow = (ev) ->
ev.preventDefault()
$nearest_row = $(this).prev()
# Show remove button in case it was hidden
$nearest_row.find('.text-array__remove').show()
$new_row = $nearest_row.clone()
$new_row.find('input').val("")
# Need to set click handler on newly created button
$remove_button = $new_row.find('.text-array__remove')
$remove_button.click removeRow
$new_row.insertBefore(this)
removeRow = (ev) ->
ev.preventDefault()
this.parentElement.remove()
hideRemoveButton()
# Need to hide button so they can't remove the only row, otherwise there would be nothing to clone.
hideRemoveButton = ->
$('.text-array').each (i, el) ->
$rows = $(el).children('.text-array__row')
if $rows.length == 1
$rows.find('.text-array__remove').hide()
$('.text-array__add').click addRow
$('.text-array__remove').click removeRow
hideRemoveButton()
Make sure the controller params list it as an array:
def user_params
params.require(:user).permit(:name, :age, { my_array: [] })
end
This example uses MetaSearch which is now deprecated but still provides a good example of custom inputs. This input actually generates two input fields, one for the lower boundary (greater than or equal to) and one for the upper (less than or equal to). For example, searching for users between the ages of 21 and 30.
# app/inputs/between_input.rb
class BetweenInput < SimpleForm::Inputs::Base
def input(wrapper_options)
field1 = @builder.number_field(:"#{attribute_name}_gteq", input_html_options)
field2 = @builder.number_field(:"#{attribute_name}_lteq", input_html_options)
# Be aware for I18n: translate the "and" here
(field1 << @builder.label(:"#{attribute_name}_lteq", 'and', class: 'separator') << field2).html_safe
end
# Make the label be for the first of the two fields
def label_target
:"#{attribute_name}_gteq"
end
end
- # app/views/users/_search.html.haml
= simple_form_for @user_search do |form|
= form.input :age, as: :between, label: "Age between"
Rather than using a select input and specifying the collection, a custom collection input type can bundle that collection and have the added benefit of including any associated input_html you care to use.
class CustomCollectionInput < SimpleForm::Inputs::CollectionSelectInput
def input(wrapper_options)
collection = Collection::LIST
label_method = :to_s
value_method = :to_s
@builder.collection_select(
attribute_name, collection, value_method, label_method,
input_options, input_html_options
)
end
def input_html_classes
super.push('custom-css-class chosen-selector')
end
end
Call in a form with
<%= f.input :column_name, as: :custom_collection %>
When inheriting from these classes you need to override input_type
so the builder can find the correct input method. Otherwise you will see an error similar to: undefined method 'collection_custom_checkboxes' for #<#SimpleForm::FormBuilder>
class CustomCheckboxesInput < SimpleForm::Inputs::CollectionCheckBoxesInput
# simple_form looks for the method "collection_#{input_type}" on the form,
# can be either check_boxes or radio_buttons
def input_type
'check_boxes'
end
end
This page was created by the OSS community and might be outdated or incomplete. Feel free to improve or update this content according to the latest versions of SimpleForm and Rails to help the next developer who visits this wiki after you.
Keep in mind to maintain the guides as simple as possible and to avoid additional dependencies that might be specific to your application or workflow (such as Haml, RSpec, Guard and similars).