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
, 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
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
'
Please enter the relevant details
';
}
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
contain a mix of fields and blocks.
Note that you must be rendering with widgets to use block rendering.
=head2 Twitter Bootstrap 2.0 rendering
The main component of Bootstrap rendering is L.
It produces the standard Bootstrap-style HTML such as:
These are the standard 'control' blocks for Bootstrap vertical and horizontal forms.
You can apply this wrapper to all of your fields by setting the widget_wrapper in the form:
has '+widget_wrapper' => ( default => 'Bootstrap' );
There is also a sample "theme": L. It sets
the widget_wrapper for you and provides a 'render_form_messages' method to render a
success/error messages section.
There are a couple of examples in the t/bootstrap directory of Bootstrap inline and search forms,
which don't use exactly the same kind of control HTML.
You can always copy the existing wrapper and add your own features, with settings provided
by the 'tags' hashref.
=head2 Rendering themes
Many of the flags and settings necessary for rendering can now be moved out into a role.
Whether you want to do that or not is a matter of style and preference. The advantage is
that it leaves the form class itself cleaner and easier to read. The disadvantage is
that your settings come from more different places.
Here's an example of a form rendering 'theme', taken from the t/bootstrap/basic.t test:
package MyApp::Form::Basic::Theme;
use Moose::Role;
# make a wrapper around the form
sub build_do_form_wrapper {1}
# set the class for the form wrapper
sub build_form_wrapper_class { ['span9'] }
# set the class for the form element
sub build_form_element_class { ['well'] }
# set various rendering tags
sub build_form_tags {
{ wrapper_tag => 'div',
before => qq{With v2.0, we have
lighter and smarter defaults for form styles. No extra markup, just
form controls.
\n},
after => '
',
}
}
# the settings in 'build_update_subfields' are merged with the field
# definitions before they are constructed
sub build_update_subfields {{
# all fields have a label but no wrapper
all => { do_wrapper => 0, do_label => 1 },
# set the element class, a placeholder in element_attr
foo => { element_class => ['span3'],
element_attr => { placeholder => 'Type something…' },
tags => { after_element =>
qq{\nAssociated help text!} } },
bar => { option_label => 'Check me out',
label_class => ['checkbox'], do_label => 0 },
submit_btn => { element_class => ['btn'] },
}}
Note that the value 'all' key in the update_subfields hashref will be merged
into the attributes used when building all of the fields.
=head2 Rendering fields
The default for most fields is a 'div' wrapper and a label. If you don't want
the wrapper, set C<< do_wrapper => 0 >>. If you don't want the label, set
C<< do_label => 0 >>.
Checkboxes are most complicated, in that the default
is to have two labels. The outer label, the one that's in the same place as the label
for other input elements, is set with C<< label => '...' >>. The inner label,
which is the equivalent of the C<< label => '...' >> in the options array used
for selects and checkbox groups, is set with C<< option_label => '...' >>.
There are a number of other 'tags' to control the presentation. See
L for more information, and
t/render/checkbox.t for examples.
Some fields by default do not render a label: Button, Submit, Reset, ButtonTag.
If you do want a label with these fields, you must set the 'do_label' flag to 1:
has_field 'foo' ( type => 'Button', do_label => 1 );
Select fields are also fairly complicated. They can be rendered with the
'Select', 'RadioGroup', and 'CheckboxGroup' widgets. Option groups are also
supported. See L;
=head2 Rendering labels
A 'standard' label is built in the field if you don't supply one. The label
can be provided in the field definition:
has_field 'foo' => ( label => 'My Foo' );
You can also provide a method to 'build' the label:
has_field 'foo' => ( build_label_method => \&build_label );
sub build_label {
my $self = shift; # field method
return '...';
}
And a method to 'wrap' the label (used by the Simple and Bootstrap wrappers):
has_field 'foo' => ( label => 'My Foo', wrap_label_method => \&wrap_label );
sub wrap_label {
my ( $self, $label ) = @_;
# or: my $label = $self->label;
return qq{$label};
}
This is particularly useful for creating labels that have links or other HTML.
The 'wrap_label_method' does no filtering or localization, so you must do that
yourself in the method if you need it.
=head2 Rendering filter
The base field class has a 'render_filter' attribute which is a coderef used to
clean the values used to fill in the form for Render::Simple and the Widgets,
and for some of the labels..
The default filter changes quote, ampersand, <, and > to the equivalent html
entities. If you wish to use some other sort of filtering, you can use the
'render_filter' method in your form, or set a coderef on individual field
objects. A 'render_filter' function in your form will be used by all fields.
Setting it for a field will just be for that field.
sub render_filter {
my $string = shift;
$string =~ s/my/MY/g; # perform some kind of transformation
return $string;
}
-- or --
has_field 'foo' => ( render_filter => sub { ... } );
The filter is called in Render::Simple and in the widgets with
C<< $self->html_filter( $fif ) >> or C<< $field->html_filter( $fif ) >>.
If you want to turn off the filter for a particular field, you can set it
to a sub that just returns the value:
has_field 'bar' => ( render_filter => sub { shift } );
If you want a label that is unfiltered, see 'wrap_label_method'.
=head1 Special rendering pseudo-fields
Also see L. Blocks may be a better
solution than pseudo-fields (i.e. fields that aren't actual form
elements).
Various 'tags' used for rendering can also be used for similar
purposes.
=head2 NonEditable
Like a Bootstrap 'non_editable' field. Displays the field's value
as a span.
has_field 'non_edit' => ( type => 'NonEditable', value => 'This is a Test' );
=head2 Display
L
You can supply an HTML string to this field, to be displayed directly. There is no
'value' associated with this field; it's a field for rendering only. The HTML
string can be built with a form or field method.
Blocks or tags will often be a better solution.
=head1 AUTHOR
FormHandler Contributors - see HTML::FormHandler
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2017 by Gerda Shank.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut