[Catalyst] Putting more in the View

Bill Moseley moseley at hank.org
Thu Feb 16 00:30:24 CET 2006


On Wed, Feb 15, 2006 at 10:36:57PM +0000, Ian Docherty wrote:
> The template is different in the two cases. In the first case it is 
> assuming a complex object together with methods is passed. In the second 
> case it is at best a complex data structure.

Well, TT can hide that because it doesn't care if it's working with
objects or a hash.  But, that's one reason for using FillInForm
because you can populate the form with data from the object or from
the previous request and not have to worry about where it comes from.

My actions look like this, say in MyApp::C::Foo::User.


/foo/user           <- list all users
/foo/user/123       <- list user 123
/foo/user/edit      <- create new user (yes, I know)
/foo/user/edit/123  <- edit user 123

My forms post back to /foo/user/edit.  I don't have a separate "save"
or "update" action.

FillInForm has its scary parts, but it does make your template very clean.  You
just include the html for the form, and don't worry about populating
the forms in the template.  Gets rid of all that ugly processing in
the templates.

You can also use HTML::Widget and Rose::HTML::Object if you don't want
to use HTML::FillInForm.  Again those solve the problem of generating
the forms and populating them.


> I accept your point that FillInForm would do this but still aim to be 
> convinced. On this point, I am not clear how FillInForm should work. If 
> for example I have a loop (for example displaying a number of User 
> contact telephone numbers for example) then this loop is populated 
> initially from a User-has-many relationship. The TT loop is controlled 
> the first time round from a User method. On subsequent form submission 
> (using sticky-forms) there is no User method, so how does TT get it's 
> loop count?

Forms are flat -- so all you need is a hash to make them sticky.  You
need to know relationships to create option lists, of course.

Maybe you need to abstract out your forms.


This is what my controllers look like for create/edit/update:


sub edit : Local {
    my ( $self, $c, $id ) = @_;

    # Create a new form object - show list if invalid $id is provided

    my $form = $c->stash->{form} = WS2::Form::Admin::Person->new( $id );


    return $c->internal_redirect('list', { message => 'Invalid Person Selected' } )
        unless $form;


    # Now validate
    if ( $c->form_posted ) {
        $form->update_from_form( $c->req->parameters );
    }
}


That sets a "form" stash variable.  $form->item has the user's object
(unless creating).  So that's available in the template.

$form->fields has the list of fields for accessing all the fields, and
$form->field('status') is one of the fields in the form (that happens
to be a radio select).  My form elements know what type they are
(text, select, multiple select) and know how to generate the html for
the field.

$form->fif returns a hash usable for HTML::FillInForm.  $form->fif
returns either the initial data form looking up the object or the
request parameters passed in to the update_from_form() method.  That
makes the form sticky.


> The View on the other hand needs to know how the Controller requires its 
> data. For example, if on validating a date string to ensure it is valid, 
> it should convert it into the system internal date format (whatever that 
> is).

How is the view passing data to the controller?  You mean through
posted data?

> Similarly it should not just pass a checkboxes value of 'on' or 
> undefined to the controller but to a boolean true or false.

Well, in my setup with a separate form object (as above) is that part
of the view or controller?  I think it as part of the controller.

My form object knows (by the ORM relationships) how to fetch options
for select lists, and now to update the object from the request
parameters.

> So, if the view was changed to use some other method that (for example) 
> used a radio button, or a drop-down, instead of a checkbox then only the 
> view would change (to process the input) and the controller would remain 
> unchanged.

In my case I just change my form object to say a field is a radio vs.
dropdown.  (Actually it's either a "multiple" or "select" and unless
forced, radio vs. drop-down depends on the number of options.)


-- 
Bill Moseley
moseley at hank.org




More information about the Catalyst mailing list