HTML-FormHandler
view release on metacpan or search on metacpan
lib/HTML/FormHandler/Manual/Rendering.pod view on Meta::CPAN
putting lots of logic into templates.
All of the rendering is designed to be easily replaced with elements of your
own, or to be replaced entirely. You can create your own rendering 'widgets'
and load them into the fields by designating the directory in the
'widget_name_space'. You could also create a completely separate renderer
that's a separate object or class that takes a form object,
or a role that is applied to your form.
Note that unless you set 'no_widgets' in the form, the rendering roles are
automatically applied. You don't need to include anything else, unless you
want to use a different renderer.
=head2 Mostly templates
The names of your fields must match the names of your FormHandler fields.
If you use compound fields, you must use the FormHandler naming convention.
Form used in examples:
package MyApp::Form::Example;
use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
has_field 'foo';
has_field 'bar';
has_field 'save' => ( type => 'Submit' );
If you have existing forms in templates or just prefer them, you can use
the 'fill-in-form' values provided with the form's 'fif' function.
my $form = MyApp::Form::Example->new;
$form->process( params => $params );
$c->stash( fif => $form->fif );
...
<form id="myform" action="/edit/example" method="post">
<label>Foo</label>
<input id="foo" name="foo" value="[% fif.foo %]">
<label>Bar</label>
<input id="bar" name="bar" value="[% fif.bar %]">
<input type="submit" name="submit" value="Save">
</form>
If you are looking for an easy way to get your fields to line up in an evenly spaced manner,
all uniformly aligned, and to do so without using templates or tables, you can externally style the
default FormHandler output with the following CSS rule (not supported in internet explorer 6).
*I<This above is useful for simple forms. Complex forms with fieldsets and other extra features>
*I<will require further styling of the HTML. The following rule is also HTML 5 compatible.>
form#id_of_your_form div div label, form#id_of_your_form div div input {
float: left;
display: inline-block;
width: 40%
} /* make sure the parent element is sized appropriately. 700px is a good width */
Going a little bit farther in using FormHandler rendering, you can render
each of the fields individually, using 'render' or 'renderx':
<form id="myform" action="/edit/example" method="post">
<fieldset><legend>My Foo</legend>
[% form.field('foo').render %]
</fieldset>
[% form.field('bar').renderx(element_class => 'cb33') %]
[% form.field('save').render %]
</form>
If you don't want the wrappers, use a widget_wrapper of 'None'.
has '+widget_wrapper' => ( default => 'None' );
Then you can provide the HTML in which the form elements are
embedded:
<div class="my_class">
[% form.field('foo').render %]
</div>
<div class="another_class">
[% form.field('bar').renderx(element_class => 'cb33') %]
</div>
You can also use the 'render_element' or 'render_elementx' methodx, if you want to leave the
wrapper in place, but sometimes render 'bare' html elements:
<div class="my_class">
[% form.field('foo').render_element %]
</div>
<div class="my_class">
[% form.field('foo').render_elementx(element_class => 'cb33') %]
</div>
If you wish to loop through the fields yourself, use the 'sorted_fields'
method, since it skips inactive fields and handles the 'order' attribute.
A set of Template Toolkit templates is also provided in the 'share'
directory. There are individual templates for each 'widget', such as
a checkbox, and there is also an all-in-one template that includes
blocks for the various 'widgets'. If you want to use these templates
you can just copy them to your template directory and specify the form
template in your controller.
See also L<HTML::FormHandler::Manual::Templates>.
=head2 Automatic rendering
If you take all the defaults, you can simply render a form with C<< $form->render >>.
[% form.render %]
or
[% form.renderx( form_element_class => ['xxx'] ) %]
This uses the L<HTML::FormHandler::Widget::Form::Simple> role, which is applied to
the form by default. You can use a different form rendering role by including
it using 'with':
with 'HTML::FormHandler::Widget::Form::Table';
has '+widget_wrapper' => ( default => 'Table' );
For the 'Table' form widget, you will also need to set the matching
Table widget_wrapper.
lib/HTML/FormHandler/Manual/Rendering.pod view on Meta::CPAN
In a role you would have to do the equivalent with an 'around' method modifier.
=head3 Repeatable field instances
The repeatable field instances are constructed internally, so it's trickier to set
things like wrapper tags. There are two ways to do it, using the 'init_contains'
attribute on the repeatable field, and using the 'update_subfields' builder:
has_field 'records' => ( type => 'Repeatable', num_when_empty => 2,
init_contains => { tags => { wrapper_tag => 'fieldset' } } );
-- or --
sub build_update_subfields { { by_flag => {
contains => { tags => { wrapper_tag => 'fieldset' }}}}}
The 'build_update_subfields' option is mainly useful if you have multiple
repeatable fields that you want to set, or if you want defaults in a base
class.
=head3 widget and widget_wrapper set to 'None'
If you want to implement the 'render' method in a custom field, you can set
'widget' to 'None' and no widget will be applied. Setting the 'widget_wrapper'
to 'None' will apply the 'None' wrapper, which simply returns the widget
rendering.
=head3 Error messages
The default is currently to display error messages next to the rendered fields,
if you're doing C<< $form->render >>. If you don't want messages next to fields,
you can set the 'no_errors' tag, as discussed in the section on 'Tags and other
settings...'.
Note that the 'None' widget wrapper, since it doesn't render anything except the
form element (input, select, etc), will not render errors next to the field.
Setting the 'do_wrapper' and 'do_label' flags to 0 will still render errors.
=head2 Blocks
When rendering, FormHandler loops through the sorted fields in the form and
executes the 'render' method on each field. Fields in FormHandler forms,
particularly those that interface with a database, are usually structured
in a way that matches the data structure. This doesn't always fit with
the way that you want to display the form.
'Blocks' provide an alternative way of structuring the display. A 'block'
is a fairly basic object that contains a 'render' method. The standard
block class, L<HTML::FormHandler::Widget::Block>, has Moose attributes to
set the HTML tag, the label, the classes, etc, plus a 'render_list'
which contains the names of a list of fields or other blocks to render.
Here is the definition of a fieldset block that contains two fields:
has_field 'foo';
has_field 'bar';
has_block 'first_fset' => ( tag => 'fieldset, label => 'Two Fields',
render_list => ['foo', 'bar'] );
The 'first_fset' block will render like this:
<fieldset><legend>Two Fields</legend>
<div>
<label>Foo</label>
<input type="text" name="foo" id="foo" value="" />
<div>
<div>
<label>Bar</label>
<input type="text" name="bar" id="bar" value="" />
<div>
</fieldset>
You can also provide a method to 'build' the block's render list
has_block 'first_fset' => ( tag => 'fieldset, label => 'Two Fields',
build_render_list_method => \&build_render_list_first_fset );
sub build_render_list_first_fset { ['foo', 'bar'] }
In order to actually get this block to be used when you render with
C<< $form->render >>, you need to supply a 'render_list' on the form
level:
sub build_render_list { ['first_fset', 'submit_btn'] }
You could also render it with C<< $form->block('first_fset')->render >>.
Blocks should be located in a widget name space, in a 'Block' directory,
or else the name should be prefixed with a '+'.
has '+widget_name_space' => ( default => sub { ['MyApp::Form::Widget'] };
has_block 'first' => ( type => 'MyBlock', ... );
The 'MyBlock' above will be found in 'MyApp::Form::Widget::Block::MyBlock'.
has_block 'intro' => ( type => '+MyApp::Form::Component::Intro' );
A block can inherit from L<HTML::FormHandler::Widget::Block>, but it doesn't
have to. At a minimum it must provide 'new' and 'render' methods. If no
'type' is specified, the block is created from the L<HTML::FormHandler::Widget::Block>
package.
The following package provides a functional block:
package MyApp::Component::Section;
sub new {
my ( $class, %args ) = @_;
return bless \%args, $class;
}
sub form {
my $self = shift;
return $self->{form};
}
sub render {
return
'<div class="intro">
<h3>Please enter the relevant details</h3>
</div>';
}
1;
When a form is rendered, it will either loop through all of the sorted_fields OR
loop through the fields and blocks listed in the 'render_list'. A render_list can
( run in 0.915 second using v1.01-cache-2.11-cpan-39bf76dae61 )