-
Notifications
You must be signed in to change notification settings - Fork 0
Adding custom input components
You may find yourself wanting to add a custom component to the normally generated set of tags that simple_form creates for each input.
In my case I wanted to show a preview of an uploaded file below the file input. This would show when editing a record with an existing file, or when an error has occured with another part of the form when adding a new record but where a file has been uploaded against that record successfully. See: carrierwave allows you to keep the file in a temporary cache in case of form validation problems on other fields.
First, create a subclass of SimpleForm::Inputs::FileInput under app/inputs:
# app/inputs/image_preview_input.rb
class ImagePreviewInput < SimpleForm::Inputs::FileInput
def input
# :preview_version is a custom attribute from :input_html hash, so you can pick custom sizes
version = input_html_options.delete(:preview_version)
out = '' # the output string we're going to build
# check if there's an uploaded file (eg: edit mode or form not saved)
if object.send("#{attribute_name}?")
# append preview image to output
out << template.image_tag(object.send(attribute_name).tap {|o| break o.send(version) if version}.send('url'))
end
# append file input. it will work accordingly with your simple_form wrappers
(out << @builder.file_field(attribute_name, input_html_options)).html_safe
end
end
Optionally, if you want to add a CSS class to all instances of the custom input, you should add input_html_classes.push 'class-name'.
Then, use it in your form:
<%= simple_form_for @some_model do |f| %>
<!-- we specify the new custom input, and we'll use the 'thumb' version of the carrierwave upload -->
<%= f.input :image, :as => :image_preview, :input_html => {:preview_version => :thumb} %>
<% end %>
If you need a better upload input specifically, you might want to check out the fancy uploads gem.
Your first step is to modify the simple_form initialiser setting config.components to call your custom component:
config.components = [ :placeholder, :label, :hint, :input, :preview, :error ]You'll find a commented out version of this config option at the top of the file in /config/initializers/simple_form.rb.
As you can see I've added a component called preview that will show after the input. In my example I've also split out the label and input components (normally label_input) because it suited my form design better.
The next step is to require a file that we're going to store in your /lib folder that will deal with displaying your custom component. Put it right at the end of the same file /config/initializers/simple_form.rb.
SimpleForm.setup do |config|
config.components = [ :placeholder, :label, :hint, :input, :preview, :error ]
end
require 'simple_form/preview_component.rb'Ok now simply make a folder in your /lib folder called simple_form and make a new file in there called preview_component.rb. Here is the contents of my preview_component.rb file:
module SimpleForm
module Components
module Preview
def preview
if input_type == :file
template.image_tag(object.send("#{attribute_name}_url"), :class => 'file_preview') if object.send("#{attribute_name}?")
end
end
end
end
module Inputs
class Base
include SimpleForm::Components::Preview
end
end
endIn this file we're essentially opening SimpleForm::Inputs::Base and including SimpleForm::Components::Preview. This module contains a method preview that first checks if the input we're dealing with is a file input, and if so, adds the preview image.
You have access to template which allows you to use view helpers, object which is the overall record object, and attribute_name which is the name of the attribute currently being dealt with. There are more variables and objects at your disposal, see: https://github.com/plataformatec/simple_form/blob/master/lib/simple_form/inputs/base.rb#L18
Many thanks to Carlos Antonio da Silva who provided me with most of this information to get me started.