Formtastic 2 Preview: Custom Inputs
Published 7 April 11 by Justin French
I’ve been pouring more hours than I care to admit into a massive refactor of Formtastic. I’m really happy with where it’s headed, so it’s time to share some of the goodies!
Custom inputs (the ability to define your own input type) has been on my list since day one, and the refactor has made it really easy. Each input is now handled by it’s own class, which obviously lets us take advantage of things like class inheritance and composition with modules.
Under the hood, when you render an input with something like this:
<%= f.input :title, :as => :number %>
We’re creating a new instance of the Formtastic::Inputs::NumberInput class and calling #to_html on it. That class looks something like this:
class NumberInput
include Base
include Base::Stringish
def to_html
input_wrapping do
label_html <<
builder.number_field(method, input_html_options)
end
end
def input_html_options
{
:min => validation_min,
:max => validation_max,
:step => validation_integer_only? ? 1 : nil
}.merge(super)
end
end
Most of the heavy lifting is done in the included modules. This class is only concerned with the things that are different about a number input compared to other “stringish” inputs like SearchInput, PhoneInput, EmailInput and of course StringInput.
In this case, we’ve added default min, max and step attributes for the <input> tag, and implemented #to_html, which calls Rails’ number_field helper. It could (and probably will) be abstracted even further before I’m done, but for now it’s all about the vibe of the thing.
Here’s the cool bit. Before instantiating Formtastic::Inputs::NumberInput, we try to instantiate a top-level class NumberInput. This means you can create a NumberInput class in app/inputs/number_input.rb, inherit from Formtastic::Inputs::NumberInput and make any modifications you want to the class. Under the hood, there’s about 55 methods available on NumberInput which you can override, but you could ultimately do anything you want by overriding #to_html:
class NumberInput < Formtastic::Inputs::NumberInput
def to_html
"Return whatever HTML string you want, however you want."
end
end
A more likely and less dramatic scenario might be to add a special class to the <li> wrapper tag, ditch those new HTML5 min, max & @step attributes and use a text input instead of the HTML5 number input. Easy:
class NumberInput < Formtastic::Inputs::NumberInput
def to_html
input_wrapping do
label_html <<
builder.text_field(method, input_html_options)
end
end
def input_html_options
super.reject { |k, v| [:min, :max, :step].include?(k) }
end
def wrapper_html_options
super.merge(:class => "#{super[:class]} special-class" )
end
end
Thank you, Ruby!
Maybe you want to alter EmailInput so that it always includes some fluffy hint text about privacy, and maybe some placeholder text. In other words, you want to define what your app needs from an email input, so that you don’t have to repeat yourself all over the app. Easy:
class EmailInput < Formtastic::Inputs::EmailInput
def hint_text
"Trust us, we never send spam and never share your email address with others."
end
def placeholder_text
"you@yours.com"
end
end
Here’s the awesome bit. You can create your own custom inputs in the same way. Here’s a few ideas:
- subclass
NumberInputto create anAgeInput - subclass
StringInputto create a jQueryDatepickerInput - redefine
DateTimeInputto be way less complicated than it is right now (perhaps as a HTML5 date picker with Javascript fallback?)
This stuff is in the master branch on Github right now. If you’ve got a little app in development, now would be a great time to take it for a spin and give me some feedback — simply bundle Formtastic from the master branch directly with the :git option, have a play, then switch back to the gem.
Perhaps now is a great time to shamelessly plug the Pledgie campaign? I’m doing this for myself, but it’d be great to know I’m also doing it for you, your boss or your clients as well.
Before you go…
Here’s some links to my most popular posts: