HTML::FormFu::Manual::Cookbook - Cooking with HTML::FormFu
Miscellaneous useful recipes for use with HTML::FormFu
Some useful info for beginners.
The current working directory (cwd) (see "load_config_file" in HTML::FormFu).
cwd
If you're using the FormConfig action attribute from Catalyst::Controller::HTML::FormFu, forms should be saved in root/forms. See "SYNOPSIS" in Catalyst::Controller::HTML::FormFu and "config_file_path" in Catalyst::Controller::HTML::FormFu for further details.
FormConfig
root/forms
Most examples given in the HTML::FormFu documentation use YAML syntax. You can use any configuration file type supported by Config::Any, but this author's preferred format is YAML.
A form can be populated by a config file by calling "load_config_file" in HTML::FormFu with the filename as an argument. The config file is converted to a perl data-structure, and then passed to "populate" in HTML::FormFu.
The config file must contain a hash-ref, with the keys corresponding to form method-names, and the values being the method arguments. For example, the following are equivalent:
--- auto_fieldset: 1 elements: - name: foo - name: bar # the above YAML is equivalent to the following perl code $form->auto_fieldset(1); $form->elements([ { name => 'foo' }, { name => 'bar' }, ]);
When writing your config file, remember that perl hashes are unordered and cannot have multiple keys with the same name.
See "load_config_file" in HTML::FormFu and "populate" in HTML::FormFu for more details.
See http://www.yaml.org/spec/ for the YAML specification.
You can run the following script to quickly view a form's markup - replace the contents of the __DATA__ section with your own YAML config.
__DATA__
#!/usr/bin/perl use strict; use warnings; use HTML::FormFu; use YAML::XS qw( Load ); my $form = HTML::FormFu->new; my $yaml = do { local $/; <DATA> }; my $data = Load($yaml); $form->populate($data); print $form; __DATA__ --- auto_fieldset: 1 elements: - type: Text name: foo
You can use the HTML::FormFu::Element::Block element, and set the tag to create any arbitrary pair of tags.
--- elements: - type: Block tag: span content_xml: "<b>Hi!</b>"
You can use "content" in HTML::FormFu::Element::Block, "content_xml" in HTML::FormFu::Element::Block or "content_loc" in HTML::FormFu::Element::Block to add any content you wish, or use "element" in HTML::FormFu::Element::Block to add elements.
You can automatically set defaults using "default_args" in HTML::FormFu, and if you set this in a Catalyst application config file, it'll take effect throughout your entire application, for example:
myapp.yml --- 'Controller::HTML::FormFu': constructor: default_args: elements: Checkbox: reverse_multi: 1 Radio: reverse_multi: 1
See "insert_before" in HTML::FormFu and "insert_after" in HTML::FormFu.
my $fieldset = $form->get_element({ type => 'Fieldset' }); $fieldset->insert_before( $form->element(\%specs), $form->get_field($name) );
Another way to approach the problem is to use multiple config files, and decide which to load at runtime:
# user_edit.yml --- elements: - type: Text name: email # user_username.yml --- elements: - type: Text name: username # user_register.yml --- load_config_file: - user_username.yml - user_edit.yml # create a user edit form, with only the email field $form->load_config_file( 'user_edit.yml' ); # create a user registration form with username and email fields $form->load_config_file( 'user_register.yml' );
You can add any arbitrary attributes to a form with "attributes" in HTML::FormFu, or to any element with "attributes" in HTML::FormFu::Element.
--- attributes_xml: onsubmit: "js_function()" elements: - type: Text name: foo attributes_xml: onchange: "js_function()"
Use HTML::FormFu::Inflator::DateTime. When the inflator is processed, it will try to create a DateTime object. An error will be returned if the supplied values do not make a valid date.
HTML::FormFu::Constraint::Regex supports Regexp::Common regular expressions:
--- elements: - type: Text name: uri constraints: - type: Regex common: [ URI, HTTP, { '-scheme': 'ftp|https?' ]
If HTML::FormFu::Constraint::Callback or HTML::FormFu::Validator::Callback isn't sufficient for your needs, you can create your own class that inherits from HTML::FormFu::Constraint or HTML::FormFu::Validator, respectively.
It should implement a validate_value method, which returns true is the value is valid, or false otherwise.
validate_value
package My::Custom::Validator; use strict; use base 'HTML::FormFu::Validator'; sub validate_value { my ( $self, $value, $params ) = @_; return 1 if value_is_valid( $value ); return; } 1;
Then add your custom validator to the form:
--- elements: - type: Text name: foo validators: - '+My::Custom::Validator'
For example, you have a radiogroup and several text fields, with different text fields being required depending on the value of the radiogroup.
This is achieved using the when attribute of a constraint:
when
constraints: - type: Length min: 8 when: field: bar values: [ 1, 3, 5 ]
In the above example, the Length constraint is only processed when the form field named "bar" has a value of either 1, 3 or 5.
You can also test for a negative condition using the not attribute:
not
constraints: - type: Length min: 8 when: field: bar values: [ 1, 3, 5 ] not: 1
Now the constraint will be processed only if the value of field "bar" is NOT 1, 3 or 5.
Note: if you rely on the value of a checkbox for a when-restricted contraint, you might want to consider setting default_empty_value for that checkbox. Take a look at HTML::FormFu::Element::_Field to learn more.
default_empty_value
Please read HTML::FormFu::Constraint for futher information.
You can use the when attribute of a constraint also to decide using a callback if the constraint should be applied.
For instance, the following (code) example shows a constraint being applied only if the value of another field contains a pattern
my $apply_if_pattern = sub { my $params = shift; return 1 if $params->{other_field} =~ m/\A ice_cream \z/xms; return 0; } $field->{constraints} = { type => 'Required', when => { callback => $apply_if_pattern, } }
Use HTML::FormFu::OutputProcessor::Indent:
--- output_processors: - Indent
Simply add a Block element in the relevant place, it defaults to a DIV tag.
DIV
--- elements: - type: Text name: user - type: Block id: foo - type: Text name: email
If you want to display an error message due to an error in your own code, such as a database check; something which isn't implemented as a Constraint or Validator; you can use a Callback Constraint.
If you don't provide your own callback routine, the default callback will always pass, regardless of user input.
You can take advantage of this by setting force_errors, to display its error message when needed.
Example config:
--- elements: - type: Text - name: email - constraints: type: Callback message: 'Email address already in use'
Example usage:
if ( $@ =~ m/duplicate entry for key 'email'/i ) { $form->get_field('email') ->get_constraint({ type => 'Callback' }) ->force_errors(1); $form->process; # then redisplay the form as normal }
This can be achieved using the form's auto_constraint_class method:
auto_constraint_class
$form->auto_constraint_class( 'constraint_%t' );
The container divs around any form field with a constraint will then have extra CSS classes added, which indicate the type of constraint and allow you to apply appropriate styling with CSS:
/* change background of labels for fields with a Required constraint */ fieldset .constraint_required label { background: #f00; }
This technique can also be used to add content before or after the fields in question (note this will not work in older browsers with more limited CSS support such as IE6):
/* add an asterisk at the end of the label for required fields */ fieldset .constraint_required label:after { content: '*' }
Some visual browsers (including IE6/7, Firefox, Opera 9) display a tooltip when a user hovers their mouse pointer over an HTML element with a "title" tag. Aural browsers may try to turn the content into speech. You can take advantage of this behaviour to provide a hint to the user about how to complete a form field.
elements: - type: Text name: country_name label: Country Name attributes: title: Name of country
The above will provide a hint when the "country_name" field receives focus. Or you could provide the hint for the container tag around both field and label:
elements: - type: Text name: country_name label: Country Name container_attributes: title: Name of country
If you have a Filter on a field, such as HTML::FormFu::Filter::Whitespace to strip leading / trailing whitespace, then if you redisplay the form the field is normally populated with the value the user originally entered.
If you would like the field to contain the filtered value, use "render_processed_value" in HTML::FormFu.
It only makes sense to use the template files if you plan on customising them, as the default string render-method is faster.
string
If you're using the Catalyst web framework, install Catalyst::Controller::HTML::FormFu and run the following command:
$ script/myapp_create.pl HTML::FormFu
This will create a directory, root/formfu, containing the HTML::FormFu template files.
root/formfu
If you use Catalyst::Controller::HTML::FormFu as a base class and you don't set HTML::FormFu's INCLUDE_PATH yourself, it will automatically be set to root/formfu if that directory exists.
If you're not using Catalyst, you can create the template files by running the following command:
$ html_formfu_deploy.pl <target-directory>
Take note that if you choose to customise your own copy of HTML::FormFu's template files, you'll need to keep track of the Changes file, when updating HTML::FormFu, so that you can update your own templates if the core templates are updated.
Changes
If you're using Catalyst::Plugin::StackTrace, make sure you're using at least version 0.09 - earlier versions had performance problems with HTML::FormFu.
0.09
HTML::FormFu
You can also use Template::Alloy instead of Template::Toolkit, it's mostly compatible, and in many cases provides a reasonable speed increase. You can do this either by setting the HTML_FORMFU_TEMPLATE_ALLOY environment variable to a true value, or by passing TEMPLATE_ALLOY to "tt_args" in HTML::FormFu:
HTML_FORMFU_TEMPLATE_ALLOY
TEMPLATE_ALLOY
tt_args: TEMPLATE_ALLOY: 1 COMPILE_DIR: /tmp COMPILE_PERL: 1
Template::Alloy's caching is off by default. Switch it on by setting either COMPILE_EXT or COMPILE_DIR. If you're running under a persistent environment such as modperl or fastcgi, you should also set COMPILE_PERL to compile the cached templates down to perl code.
COMPILE_EXT
COMPILE_DIR
COMPILE_PERL
Of cource, if you wish you can still use Template::Toolkit to process your own application templates, letting Template::Alloy process just the HTML::FormFu templates.
To reduce the runtime for each form that uses a previously unused element or processor - at the expense of greater memory usage - you can preload all FormFu modules - this is only recommended for persistent environments such as modperl or fastcgi:
use HTML::FormFu::Preload;
See the following:
"retain_default" in HTML::FormFu::Element::_Field, "force_default" in HTML::FormFu::Element::_Field
Will Hawes wdhawes@gmail.com
wdhawes@gmail.com
Carl Franks cfranks@cpan.org
cfranks@cpan.org
This document is free, you can redistribute it and/or modify it under the same terms as Perl itself.
To install HTML::FormFu, copy and paste the appropriate command in to your terminal.
cpanm
cpanm HTML::FormFu
CPAN shell
perl -MCPAN -e shell install HTML::FormFu
For more information on module installation, please visit the detailed CPAN module installation guide.