logo
Free, unlimited AI code reviews that run on commit
git-lrc git-lrc GitHub Install Now We'd appreciate a star git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

HTML::FormFu::Manual::Cookbook - Cooking with HTML::FormFu

Advanced Customisation

InstallingtheTTtemplates
       It only makes sense to use the template files if you plan on customising them, as the default "string"
       render-method is faster.

       As of "HTML::FormFu v1.00", TT is no longer listed a required prerequisite - so you'll need to install it
       manually if you with to use the template files.

       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.

       If you extend Catalyst::Controller::HTML::FormFu 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.

Application-Wide Default Values

       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:
                   Textarea:
                     rows: 10

Author

       Carl Franks <cpan@fireartist.com>

Authors

       Will Hawes "wdhawes@gmail.com"

       Carl Franks "cfranks@cpan.org"

Building A Form

Quicksingle-fileprototypes
       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.

           #!/usr/bin/perl
               use warnings;
           use HTML::FormFu;
           use YAML::XS qw( LoadFile );

           my $form = HTML::FormFu->new;
           my $data = LoadFile(\*DATA);

           $form->populate($data);

           print $form;

           __DATA__
           ---
           auto_fieldset: 1
           elements:
             - type: Text
               name: foo

   UnsupportedHTMLtags
       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.

Description

       Miscellaneous useful recipes for use with HTML::FormFu

Display

Customerrormessages
       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
           }

   Highlightrequiredfields(orfieldswithcertaintypesofconstraint)
       This can be achieved using the form's "auto_constraint_class" method:

           $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: '*'
           }

   Addapopuphinttoafield
       Most 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: URL
               name: url
               label: Website
               title: 'Must start with http:// or https://'

       The above will provide a hint when the "url" field receives focus.  Or you could provide the hint for the
       container tag around both field and label:

           elements:
             - type: URL
               name: url
               label: Website
               container_attributes:
                   title: 'Must start with http:// or https://'

   Displayfilteredvalues
       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.

   MultipleformsusingCatalyst::Controller::HTML::FormFu
       Sometimes you need to display multiple forms on a single page. If you try to use FormConfig on several
       actions in a chain, or similar, they all use "$c->stash->{form}" to store the form, hence you only get
       the last form.

       One way to work around such problems is to do a little of the work yourself:

       In this example we have a login_form that we want on every page

           # root/forms/login.yml:
           ---
               indicator: username
               elements:
                   -
                       type: Text
                       name: username
                       constraints:
                           - Required
           ...

       We also have an edit-form

           # root/forms/foo/edit.yml
           ---
               indicator: foo
               elements:
               -
                   type: Text
                   name: foo
                   constraints:
                       - Required
           ...

       In this example, we want the login form to appear on every page, so we load this in the top-most auto
       action:

           package MyApp::Controller::Root;

           BEGIN { extends 'Catalyst::Controller::HTML::FormFu'; }

           sub auto : Private {
               my ($self, $c) = @_;

               # We want to utilize a lot of the magic that the controller
               # gives us, so therefore we call $self->form like this

               my $login_form = $self->form;
               $login_form->load_config_file('login.yml');

               # Notice how we put it into another stash var, not 'form'
               $c->stash->{login_form} = $login_form;
               unless ($c->user_exists) {

                   $login_form->process();

                   if ($login_form->submitted_and_valid) {

                       # Since we set indicator, we should only end up here if we
                       # have a username in the form
                       $c->authenticate({
                           username => $login_form->param_value('username'),
                           password => $login_form->param_value('password'),
                       });
                   }

               }
           }

       Any other page that wants to load another form, can now do so freely:

           package MyApp::Controller::Foo;

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

               my $form = $c->stash->{form};
               if ($form->submitted_and_valid) {
                   # Do whatever you want with it :p
               }
           }

       In the view we now have two stash-variables:

       In root/foo/edit.tt:
           [% login_form %]
           <h2>edit</h2>
           [% form %]

Faqs

Forceanelementtoalwayshaveacertainvalue
       See the following:

       "retain_default" in HTML::FormFu::Role::Element::Field, "force_default" in
       HTML::FormFu::Role::Element::Field

Form Validation

Checkvaliddates
       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.

   CheckvalidURI/URLs
       See HTML::FormFu::Element::URL or HTML::FormFu::Constraint::Regex.

   Implementacustomconstraint/validator
       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.

           package My::Custom::Validator;
           use Moose;
           extends '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'

   Constrainoneformfieldbasedonthevalueofanother
       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:

           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:

           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::Role::Element::Field to
       learn more.

       Please read HTML::FormFu::Constraint for further information.

   Constrainoneformfieldbasedonthereturnvalueofacallback
       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,
               }
           }

       Please read HTML::FormFu::Constraint for further information.

Getting Started

       Some useful info for beginners.

   Defaultsearchpathsforconfigfiles
       The current working directory ("cwd") (see "load_config_file" in HTML::FormFu).

       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.

   YAML
       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.

Html Markup

IndentedHTML
       Use HTML::FormFu::OutputProcessor::Indent:

           ---
           output_processors:
             - Indent

   Addablankdiv(e.g.forAJAXpurposes)
       Simply add a Block element in the relevant place, it defaults to a "DIV" tag.

           ---
           elements:
             - type: Text
               name: user

             - type: Block
               id: foo

             - type: Text
               name: email

Modifying A Form

Insertanewfieldbeforeexistingformfields
       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' );

   FormandFieldattributes
       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()"

Name

       HTML::FormFu::Manual::Cookbook - Cooking with HTML::FormFu

Performance

Catalyst::Plugin::StackTrace
       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".

   Template::Alloy
       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:

           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.

       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.

   HTML:FormFu::Preload
       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;

Version

       version 2.07

See Also