[Catalyst] Rails-like form helpers
Bill Moseley
moseley at hank.org
Thu Sep 21 14:46:13 CEST 2006
On Thu, Sep 21, 2006 at 10:25:37AM +0100, Jon Warbrick wrote:
> person, telephone_number and email_address have multiple columns. person
> has_many telephone_numbers, person has_many email_addresses. I want a form
> to manage information about a particular person, including the ability to
> update existing telephone numbers and email addresses, and with buttons to
> delete any particular number and to add new ones. I don't think HTMLWidget
> can do that (though I'd be happy to be proved wrong).
The form code I use handles this -- by looking at the relationships of
the object its updating. One-to-many relationships end up as
drop-downs or radio selects (depending on the size of the option list)
and many-to-many are either checkbox groups or multi-select drop-
downs.
I can handle multi-widget fields (area code + prefix + number or date
+ time) but I don't use those -- I just uses simple text input fields
and parse and validate. (It also drives me crazy when I see
instructions on fields "Enter credit card number without the dashes".)
You should check out Rose::HTML::Objects if you have not already.
> There is also the issue that a complex form it may need careful manual
> layout of the various controls to make it usable. As I see it this is
> something for the designer to do, working in the relevant templates,
Yes, my forms code doesn't do any layout of the fields. I do that
manually. I always seem to need to hand tweak the layout of the
forms.
Also, my form code doesn't generate the actual html -- again, that's
done in a separate template. Most of the formatting is with css, but
I can use a different form template if I want to change the field
generation in ways the css can't handle.
My forms are all (well almost all) separate modules. So my
controllers looks like this:
sub edit : Local {
my ( $self, $c, $id ) = @_;
$c->stash->{form} = WS2::Form::Admin::Organization->new( $id );
# Now validate
$c->stash->{form}->update_from_form( $c->req->parameters )
if $c->form_posted;
}
With the form module:
package WS2::Form::Admin::Organization;
use strict;
use warnings;
use base 'Form::Model::CDBI';
# Define the object class that this form handles
sub object_class { 'DB::Organization' }
sub profile {
my ( $self ) = @_;
return {
required => {
name => 'Text',
active => 'Boolean',
organization_type => 'Select',
groups => 'Multiple',
},
optional => {
parent_organization => 'Select',
contact => 'Text',
email => 'Email',
phone => 'Phone',
address1 => 'Text',
address2 => 'Text',
city => 'Text',
state => 'Select',
zip => 'USZipcode',
url => 'URL',
comment => 'TextArea',
},
dependency => [
[qw/ address1 city state zip /],
],
};
}
# extra validation can be here:
sub validate_foo {
my ( $form, $field ) = @_;
$field->add_error('Foo must be "bar"')
unless $field->value eq 'bar';
}
1;
Then finally, the form that handles the above would looks something
like:
[% # Form to edit an oranization
item = form.item;
page.title = 'Organization: ' _ (item ? item.name : 'New Entry');
page_heading;
page_link( 'list', 'list all organizations' );
WRAPPER form_wrapper; PROCESS fields; END;
%]
[% BLOCK fields;
"<fieldset><legend>Organization Information</legend>";
field('Organization Name', 'name');
field('Organization Type', 'organization_type' );
field('Organization Active', 'active');
field('Member Of Groups', 'groups' );
field('Parent Organization', 'parent_organization' );
field('Contact Person', 'contact');
field('Phone', 'phone',
'Please enter the number to reach the contact');
field('Email', 'email');
field('URL', 'url');
"</fieldset>";
"<fieldset><legend>Mailing Address</legend>";
field('Address line 1', 'address1' );
field('Address line 2', 'address2' );
city_state_zip(); # does ajax updated zip-lookup.
"</fieldset>";
END %]
--
Bill Moseley
moseley at hank.org
More information about the Catalyst
mailing list