HTML::FormFu - Handles forms, so you don't have to
Today you'll get to play with HTML forms, without the usual nausea.
HTML::FormFu handles form rendering, validation, filtering and other common form tasks, but keeps your controller code clean by using external config files for everything.
Getting started
First thing you need are the actual modules, so get them off CPAN :
- * HTML::FormFu >= 0.02002
- * Catalyst::Controller::HTML::FormFu >= 0.02000
You'll also need a Catalyst app to play with. You can get a pretty standard one here:
svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Advent07FormFu/start/Fu
Fu handles a simple person database, you should check how a person is defined in Fu::Schema::Result::Person
.
Click around http://localhost:3000 once you start script/fu_server.pl
.
Next step: implementing /person/add
and /person/edit
, of course.
Your first form
A FormFu object can be created from a config file that can be parsed by Config::Any (we'll just use YAML).
Catalyst::Controller::HTML::FormFu is a bit of glue that handles this, using config files from Fu/root/forms
.
In order to use it, just replace the base class for your Person controller:
use base 'Catalyst::Controller::HTML::FormFu';
By adding the FormConfig label to an action, you'll get a FormFu object in your stash,
using root/forms/mycontroller/myaction.yml
as a config file.
Here's the code for adding persons:
sub add : Local FormConfig { my ($self, $c) = @_; my $form = $c->stash->{form}; if ($form->submitted_and_valid) { my $person = $c->model('DB::Person')->new_result({}); $form->save_to_model($person); $c->response->redirect($c->uri_for('/')); $c->detach; } }
As you can see, FormFu can perform some DBIx::Class magick, you should read more about in HTML::FormFu::Model::DBIC
When printed, a FormFu object renders the HTML, so the template is just:
<h1> Add someone </h1> <p><a href="[% c.uri_for('/') %]">Back to your buddies</a> </p> [% form %]
And the config file, root/forms/person/add.yml
:
--- indicator: submit auto_fieldset: { legend : 'Person information' } elements: - type: Text name: name label: Name constraints: - Required - type: Text name: email label: Email constraints: - Required - Email - type: Text name: phone label: Phone constraints: - Required - type: Radiogroup label: Boy or girl? :) name: gender auto_id: "%n_%c" options: - [ 'm', 'M' ] - [ 'f', 'F' ] constraints: - Required - type: Submit name: submit value: OK constraints: - SingleValue
The config options are all described in HTML::FormFu's fine manual . You should also read about the constraints in HTML::FormFu::Constraint .
A touch of style
Here's some basic CSS in static/styles.css
to make your forms less ugly. Fortunately the
generated HTML code gives you a lot of selectors to play with:
form { width: 30em; } .submit { display: block; } .error { color: #C00; display: block; background-color: #FFE; padding: 5px; margin: 2px 0px; border: 1px dotted #F00; } label { display: block; } .radiogroup span { display: block } .radiogroup label { display: inline; }
Finish the app
The edit form is not much different, so we should just use the same config:
sub edit : Local FormConfig('person/add.yml') { my ($self, $c, $id) = @_; $id =~ /\d+/ or die 'invalid id'; my $person = $c->stash->{person} = $c->model('DB::Person')->find($id) or die "person $id not found"; my $form = $c->stash->{form}; if ($form->submitted_and_valid) { $form->save_to_model($person); $c->response->redirect($c->uri_for('/')); $c->detach; } elsif (! $form->submitted ) { $form->defaults_from_model($person); } }
Just add [% form %]
to your template and you're done.
You can also checkout the finished application, to compare notes:
svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/Advent07FormFu/final/Fu
Bonus tips
Filters
You can add filters to your form. For instance, if you want to allow your users to write the phone number as they feel like (with dashes and slashes and brackets) , but want to store it in a standard way in your database, you could use HTML::FormFu::Filter::NonNumeric to strip the extra chars. Read more about adding filters in HTML::FormFu::Filter
More DBIx::Class Magick
HTML::FormFu knows a bit more than just populating a form and saving to a Row object. It can also automatically handle DBIx::Class relationships for you, like adding/editing/removing child objects or creating many-to-many associations. Read more about this in HTML::FormFu::Model::DBIC
Handling Image Uploads
HTML::FormFu::Imager will resize and validate uploaded images, and inflate the uploaded files into Imager objects.
What now?
Most importantly, you should read the actual HTML::FormFu documentation, but also don't forget to subscribe to the friendly mailing list at http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/html-formfu.
You'll also find a lot of examples and solutions in HTML::FormFu::Manual::Cookbook.
AUTHOR
Bogdan Lucaciu <bogdan@sns.ro>
System & Network Solutions