Skip to content

Commit

Permalink
Allow validation classes on input_field
Browse files Browse the repository at this point in the history
This PR is similar to this one heartcombo#1552.
It allows validation classes on `input_field`.

To get this work I added two configs for the Simple Form:
`input_field_error_class` and `input_field_valid_class`. Once the user
adds a class for these configs, the configured classes will be rendered
according to the form validation.

- Setup the `input_field` classes.
```ruby
SimpleForm.setup do |config|
  config.input_field_valid_class = 'is-valid'
  config.input_field_error_class = 'is-invalid'
end
```

- Build the form.
```erb
<%= simple_form_for @Product do |f| %>
  <%= f.input_field :name %>

  <div class="form-actions">
    <%= f.button :submit %>
  </div>
<% end %>
```
- When the validation happening, the input will be rendered with the
validation classes.
```HTML
<-- Valid example -->
<input class=" is-valid string required" type="text" value="PS4" name="product[name]" id="product_name">

<-- Invalid example -->
<input class=" is-invalid string required" type="text" value="" name="product[name]" id="product_name">
```
  • Loading branch information
feliperenan committed Apr 4, 2018
1 parent 102b9eb commit fad0393
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Add support for citext, hstore, json & jsonb column types. [@swrobel](https://github.com/swrobel)
* Add :valid_class on input wrapper when value is present and valid [@aeberlin](https://github.com/aeberlin), [@m5o](https://github.com/m5o)
* Allow :valid_class to inputs when value is present and valid. [@m5o](https://github.com/m5o)
* Allow validation classes on input_field. [@feliperenan](https://github.com/feliperenan)

### Bug fix
* Fix horizontal form label position, from right to text-right. [@cavpollo](https://github.com/cavpollo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,8 @@

# Defines which i18n scope will be used in Simple Form.
# config.i18n_scope = 'simple_form'

# Defines validation classes to the input_field. By default it's nil.
# config.input_field_valid_class = 'is-valid'
# config.input_field_error_class = 'is-invalid'
end
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,8 @@
date: :multi_select,
time: :multi_select
}

# Defines validation classes to the input_field. By default it's nil.
# config.input_field_valid_class = 'is-valid'
# config.input_field_error_class = 'is-invalid'
end
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,8 @@

# The default wrapper to be used by the FormBuilder.
config.default_wrapper = :vertical_form

# Defines validation classes to the input_field. By default it's nil.
# config.input_field_valid_class = 'is-valid'
# config.input_field_error_class = 'is-invalid'
end
6 changes: 6 additions & 0 deletions lib/simple_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ def self.configured? #:nodoc:
mattr_accessor :i18n_scope
@@i18n_scope = 'simple_form'

mattr_accessor :input_field_error_class
@@input_field_error_class = nil

mattr_accessor :input_field_valid_class
@@input_field_valid_class = nil

# Retrieves a given wrapper
def self.wrapper(name)
@@wrappers[name.to_s] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}"
Expand Down
51 changes: 50 additions & 1 deletion lib/simple_form/form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,29 @@ def input(attribute_name, options = {}, &block)
# <input class="string required" id="user_name" maxlength="100"
# name="user[name]" type="text" value="Carlos" />
#
# It also support validation classes once it is configured.
#
# # config/initializers/simple_form.rb
# SimpleForm.setup do |config|
# config.input_field_valid_class = 'is-valid'
# config.input_field_error_class = 'is-invalid'
# end
#
# simple_form_for @user do |f|
# f.input_field :name
# end
#
# When the validation happens, the input will be rendered with
# the class configured according to the validation:
#
# - when the input is valid:
#
# <input class="is-valid string required" id="user_name" value="Carlos" />
#
# - when the input is invalid:
#
# <input class="is-invalid string required" id="user_name" value="" />
#
def input_field(attribute_name, options = {})
components = (wrapper.components.map(&:namespace) & ATTRIBUTE_COMPONENTS)

Expand All @@ -147,7 +170,7 @@ def input_field(attribute_name, options = {})

input = find_input(attribute_name, options)
wrapper = find_wrapper(input.input_type, options)
components = components.concat([:input]).map { |component| SimpleForm::Wrappers::Leaf.new(component) }
components = build_input_field_components(components.push(:input))

SimpleForm::Wrappers::Root.new(components, wrapper.options.merge(wrapper: false)).render input
end
Expand Down Expand Up @@ -646,5 +669,31 @@ def attempt_mapping_with_custom_namespace(input_name)

nil
end

def build_input_field_components(components)
components.map do |component|
if component == :input
SimpleForm::Wrappers::Leaf.new(component, build_input_field_options)
else
SimpleForm::Wrappers::Leaf.new(component)
end
end
end

def build_input_field_options
input_field_options = {}
valid_class = SimpleForm.input_field_valid_class
error_class = SimpleForm.input_field_error_class

if error_class.present?
input_field_options[:error_class] = error_class
end

if valid_class.present?
input_field_options[:valid_class] = valid_class
end

input_field_options
end
end
end
25 changes: 25 additions & 0 deletions test/form_builder/input_field_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,29 @@ def with_input_field_for(object, *args)
assert_select 'input[readonly="readonly"]'
end
end

test 'adds valid class to input_field when it is configured' do
swap SimpleForm, input_field_valid_class: 'is-valid' do
@user.instance_eval { undef errors }
with_input_field_for @user, :name

assert_select 'input.string.required.is-valid'
end
end

test 'adds error class to input_field when it is configured' do
swap SimpleForm, input_field_error_class: 'is-invalid' do
with_input_field_for @user, :name

assert_select 'input.string.required.is-invalid'
end
end

test 'does not add validation classes to input_field when it is not configured' do
swap SimpleForm, input_field_error_class: nil, input_field_valid_class: nil do
with_input_field_for @user, :name

assert_select 'input.string.required'
end
end
end

0 comments on commit fad0393

Please sign in to comment.