.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "HTML::FormFu::Manual::Cookbook 3pm" .TH HTML::FormFu::Manual::Cookbook 3pm "2016-10-29" "perl v5.24.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" HTML::FormFu::Manual::Cookbook \- Cooking with HTML::FormFu .SH "VERSION" .IX Header "VERSION" version 2.05 .SH "DESCRIPTION" .IX Header "DESCRIPTION" Miscellaneous useful recipes for use with HTML::FormFu .SH "GETTING STARTED" .IX Header "GETTING STARTED" Some useful info for beginners. .SS "Default search paths for config files" .IX Subsection "Default search paths for config files" The current working directory (\f(CW\*(C`cwd\*(C'\fR) (see \*(L"load_config_file\*(R" in HTML::FormFu). .PP If you're using the \f(CW\*(C`FormConfig\*(C'\fR action attribute from Catalyst::Controller::HTML::FormFu, forms should be saved in \f(CW\*(C`root/forms\*(C'\fR. See \*(L"\s-1SYNOPSIS\*(R"\s0 in Catalyst::Controller::HTML::FormFu and \&\*(L"config_file_path\*(R" in Catalyst::Controller::HTML::FormFu for further details. .SS "\s-1YAML\s0" .IX Subsection "YAML" Most examples given in the HTML::FormFu documentation use \s-1YAML\s0 syntax. You can use any configuration file type supported by Config::Any, but this author's preferred format is \s-1YAML.\s0 .PP A form can be populated by a config file by calling \&\*(L"load_config_file\*(R" in HTML::FormFu with the filename as an argument. The config file is converted to a perl data-structure, and then passed to \&\*(L"populate\*(R" in HTML::FormFu. .PP 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: .PP .Vb 5 \& \-\-\- \& 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 => \*(Aqfoo\*(Aq }, \& { name => \*(Aqbar\*(Aq }, \& ]); .Ve .PP When writing your config file, remember that perl hashes are unordered and cannot have multiple keys with the same name. .PP See \*(L"load_config_file\*(R" in HTML::FormFu and \*(L"populate\*(R" in HTML::FormFu for more details. .PP See for the \s-1YAML\s0 specification. .SH "BUILDING A FORM" .IX Header "BUILDING A FORM" .SS "Quick single-file prototypes" .IX Subsection "Quick single-file prototypes" You can run the following script to quickly view a form's markup \- replace the contents of the \f(CW\*(C`_\|_DATA_\|_\*(C'\fR section with your own \s-1YAML\s0 config. .PP .Vb 5 \& #!/usr/bin/perl \& use strict; \& use warnings; \& use HTML::FormFu; \& use YAML::XS qw( LoadFile ); \& \& my $form = HTML::FormFu\->new; \& my $data = LoadFile(\e*DATA); \& \& $form\->populate($data); \& \& print $form; \& \& _\|_DATA_\|_ \& \-\-\- \& auto_fieldset: 1 \& elements: \& \- type: Text \& name: foo .Ve .SS "Unsupported \s-1HTML\s0 tags" .IX Subsection "Unsupported HTML tags" You can use the HTML::FormFu::Element::Block element, and set the tag to create any arbitrary pair of tags. .PP .Vb 5 \& \-\-\- \& elements: \& \- type: Block \& tag: span \& content_xml: "Hi!" .Ve .PP You can use \*(L"content\*(R" in HTML::FormFu::Element::Block, \&\*(L"content_xml\*(R" in HTML::FormFu::Element::Block or \&\*(L"content_loc\*(R" in HTML::FormFu::Element::Block to add any content you wish, or use \*(L"element\*(R" in HTML::FormFu::Element::Block to add elements. .SH "Application-wide default values" .IX Header "Application-wide default values" You can automatically set defaults using \*(L"default_args\*(R" in HTML::FormFu, and if you set this in a Catalyst application config file, it'll take effect throughout your entire application, for example: .PP .Vb 8 \& myapp.yml \& \-\-\- \& \*(AqController::HTML::FormFu\*(Aq: \& constructor: \& default_args: \& elements: \& Textarea: \& rows: 10 .Ve .SH "MODIFYING A FORM" .IX Header "MODIFYING A FORM" .SS "Insert a new field before existing form fields" .IX Subsection "Insert a new field before existing form fields" See \*(L"insert_before\*(R" in HTML::FormFu and \*(L"insert_after\*(R" in HTML::FormFu. .PP .Vb 1 \& my $fieldset = $form\->get_element({ type => \*(AqFieldset\*(Aq }); \& \& $fieldset\->insert_before( \& $form\->element(\e%specs), \& $form\->get_field($name) \& ); .Ve .PP Another way to approach the problem is to use multiple config files, and decide which to load at runtime: .PP .Vb 5 \& # 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( \*(Aquser_edit.yml\*(Aq ); \& \& # create a user registration form with username and email fields \& \& $form\->load_config_file( \*(Aquser_register.yml\*(Aq ); .Ve .SS "Form and Field attributes" .IX Subsection "Form and Field attributes" You can add any arbitrary attributes to a form with \&\*(L"attributes\*(R" in HTML::FormFu, or to any element with \&\*(L"attributes\*(R" in HTML::FormFu::Element. .PP .Vb 8 \& \-\-\- \& attributes_xml: \& onsubmit: "js_function()" \& elements: \& \- type: Text \& name: foo \& attributes_xml: \& onchange: "js_function()" .Ve .SH "FORM VALIDATION" .IX Header "FORM VALIDATION" .SS "Check valid dates" .IX Subsection "Check valid dates" 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. .SS "Check valid \s-1URI /\s0 URLs" .IX Subsection "Check valid URI / URLs" See HTML::FormFu::Element::URL or HTML::FormFu::Constraint::Regex. .SS "Implement a custom constraint / validator" .IX Subsection "Implement a custom constraint / 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. .PP It should implement a \f(CW\*(C`validate_value\*(C'\fR method, which returns true is the value is valid, or false otherwise. .PP .Vb 3 \& package My::Custom::Validator; \& use Moose; \& extends \*(AqHTML::FormFu::Validator\*(Aq; \& \& sub validate_value { \& my ( $self, $value, $params ) = @_; \& \& return 1 if value_is_valid( $value ); \& \& return; \& } \& \& 1; .Ve .PP Then add your custom validator to the form: .PP .Vb 6 \& \-\-\- \& elements: \& \- type: Text \& name: foo \& validators: \& \- \*(Aq+My::Custom::Validator\*(Aq .Ve .SS "Constrain one form field based on the value of another" .IX Subsection "Constrain one form field based on the value of another" For example, you have a radiogroup and several text fields, with different text fields being required depending on the value of the radiogroup. .PP This is achieved using the \f(CW\*(C`when\*(C'\fR attribute of a constraint: .PP .Vb 6 \& constraints: \& \- type: Length \& min: 8 \& when: \& field: bar \& values: [ 1, 3, 5 ] .Ve .PP In the above example, the Length constraint is only processed when the form field named \*(L"bar\*(R" has a value of either 1, 3 or 5. .PP You can also test for a negative condition using the \f(CW\*(C`not\*(C'\fR attribute: .PP .Vb 7 \& constraints: \& \- type: Length \& min: 8 \& when: \& field: bar \& values: [ 1, 3, 5 ] \& not: 1 .Ve .PP Now the constraint will be processed only if the value of field \*(L"bar\*(R" is \s-1NOT 1, 3\s0 or 5. .PP Note: if you rely on the value of a checkbox for a when-restricted contraint, you might want to consider setting \f(CW\*(C`default_empty_value\*(C'\fR for that checkbox. Take a look at HTML::FormFu::Role::Element::Field to learn more. .PP Please read HTML::FormFu::Constraint for further information. .SS "Constrain one form field based on the return value of a callback" .IX Subsection "Constrain one form field based on the return value of a callback" You can use the \f(CW\*(C`when\*(C'\fR attribute of a constraint also to decide using a callback if the constraint should be applied. .PP For instance, the following (code) example shows a constraint being applied only if the value of another field contains a pattern .PP .Vb 5 \& my $apply_if_pattern = sub { \& my $params = shift; \& return 1 if $params\->{other_field} =~ m/\eA ice_cream \ez/xms; \& return 0; \& }; \& \& $field\->{constraints} = { \& type => \*(AqRequired\*(Aq, \& when => { \& callback => $apply_if_pattern, \& } \& } .Ve .PP Please read HTML::FormFu::Constraint for further information. .SH "HTML MARKUP" .IX Header "HTML MARKUP" .SS "Indented \s-1HTML\s0" .IX Subsection "Indented HTML" Use HTML::FormFu::OutputProcessor::Indent: .PP .Vb 3 \& \-\-\- \& output_processors: \& \- Indent .Ve .SS "Add a blank div (e.g. for \s-1AJAX\s0 purposes)" .IX Subsection "Add a blank div (e.g. for AJAX purposes)" Simply add a Block element in the relevant place, it defaults to a \f(CW\*(C`DIV\*(C'\fR tag. .PP .Vb 4 \& \-\-\- \& elements: \& \- type: Text \& name: user \& \& \- type: Block \& id: foo \& \& \- type: Text \& name: email .Ve .SH "DISPLAY" .IX Header "DISPLAY" .SS "Custom error messages" .IX Subsection "Custom error messages" 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. .PP If you don't provide your own callback routine, the default callback will always pass, regardless of user input. .PP You can take advantage of this by setting force_errors, to display its error message when needed. .PP Example config: .PP .Vb 7 \& \-\-\- \& elements: \& \- type: Text \& \- name: email \& \- constraints: \& type: Callback \& message: \*(AqEmail address already in use\*(Aq .Ve .PP Example usage: .PP .Vb 1 \& if ( $@ =~ m/duplicate entry for key \*(Aqemail\*(Aq/i ) { \& \& $form\->get_field(\*(Aqemail\*(Aq) \& \->get_constraint({ type => \*(AqCallback\*(Aq }) \& \->force_errors(1); \& \& $form\->process; \& # then redisplay the form as normal \& } .Ve .SS "Highlight required fields (or fields with certain types of constraint)" .IX Subsection "Highlight required fields (or fields with certain types of constraint)" This can be achieved using the form's \f(CW\*(C`auto_constraint_class\*(C'\fR method: .PP .Vb 1 \& $form\->auto_constraint_class( \*(Aqconstraint_%t\*(Aq ); .Ve .PP The container divs around any form field with a constraint will then have extra \&\s-1CSS\s0 classes added, which indicate the type of constraint and allow you to apply appropriate styling with \s-1CSS:\s0 .PP .Vb 4 \& /* change background of labels for fields with a Required constraint */ \& fieldset .constraint_required label { \& background: #f00; \& } .Ve .PP 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 \s-1CSS\s0 support such as \s-1IE6\s0): .PP .Vb 4 \& /* add an asterisk at the end of the label for required fields */ \& fieldset .constraint_required label:after { \& content: \*(Aq*\*(Aq \& } .Ve .SS "Add a popup hint to a field" .IX Subsection "Add a popup hint to a field" Most display a tooltip when a user hovers their mouse pointer over an \s-1HTML\s0 element with a \*(L"title\*(R" 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. .PP .Vb 5 \& elements: \& \- type: URL \& name: url \& label: Website \& title: \*(AqMust start with http:// or https://\*(Aq .Ve .PP The above will provide a hint when the \*(L"url\*(R" field receives focus. Or you could provide the hint for the container tag around both field and label: .PP .Vb 6 \& elements: \& \- type: URL \& name: url \& label: Website \& container_attributes: \& title: \*(AqMust start with http:// or https://\*(Aq .Ve .SS "Display filtered values" .IX Subsection "Display filtered values" 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. .PP If you would like the field to contain the filtered value, use \&\*(L"render_processed_value\*(R" in HTML::FormFu. .SS "Multiple forms using Catalyst::Controller::HTML::FormFu" .IX Subsection "Multiple forms using Catalyst::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 \f(CW\*(C`$c\->stash\->{form}\*(C'\fR to store the form, hence you only get the last form. .PP One way to work around such problems is to do a little of the work yourself: .PP In this example we have a login_form that we want on every page .PP .Vb 10 \& # root/forms/login.yml: \& \-\-\- \& indicator: username \& elements: \& \- \& type: Text \& name: username \& constraints: \& \- Required \& ... .Ve .PP We also have an edit-form .PP .Vb 10 \& # root/forms/foo/edit.yml \& \-\-\- \& indicator: foo \& elements: \& \- \& type: Text \& name: foo \& constraints: \& \- Required \& ... .Ve .PP In this example, we want the login form to appear on every page, so we load this in the top-most auto action: .PP .Vb 1 \& package MyApp::Controller::Root; \& \& BEGIN { extends \*(AqCatalyst::Controller::HTML::FormFu\*(Aq; } \& \& 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(\*(Aqlogin.yml\*(Aq); \& \& # Notice how we put it into another stash var, not \*(Aqform\*(Aq \& $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(\*(Aqusername\*(Aq), \& password => $login_form\->param_value(\*(Aqpassword\*(Aq), \& }); \& } \& \& } \& } .Ve .PP Any other page that wants to load another form, can now do so freely: .PP .Vb 1 \& 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 \& } \& } .Ve .PP In the view we now have two stash-variables: .PP In \fIroot/foo/edit.tt\fR: [% login_form %]

edit

[% form %] .SH "ADVANCED CUSTOMISATION" .IX Header "ADVANCED CUSTOMISATION" .SS "Installing the \s-1TT\s0 templates" .IX Subsection "Installing the TT templates" It only makes sense to use the template files if you plan on customising them, as the default \f(CW\*(C`string\*(C'\fR render-method is faster. .PP As of \f(CW\*(C`HTML::FormFu v1.00\*(C'\fR, \s-1TT\s0 is no longer listed a required prerequisite \- so you'll need to install it manually if you with to use the template files. .PP If you're using the Catalyst web framework, install Catalyst::Controller::HTML::FormFu and run the following command: .PP .Vb 1 \& $ script/myapp_create.pl HTML::FormFu .Ve .PP This will create a directory, \f(CW\*(C`root/formfu\*(C'\fR, containing the HTML::FormFu template files. .PP If you extend Catalyst::Controller::HTML::FormFu and you don't set HTML::FormFu's \s-1INCLUDE_PATH\s0 yourself, it will automatically be set to \f(CW\*(C`root/formfu\*(C'\fR if that directory exists. .PP If you're not using Catalyst, you can create the template files by running the following command: .PP .Vb 1 \& $ html_formfu_deploy.pl .Ve .PP 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 \f(CW\*(C`Changes\*(C'\fR file, when updating HTML::FormFu, so that you can update your own templates if the core templates are updated. .SH "PERFORMANCE" .IX Header "PERFORMANCE" .SS "Catalyst::Plugin::StackTrace" .IX Subsection "Catalyst::Plugin::StackTrace" If you're using Catalyst::Plugin::StackTrace, make sure you're using at least version \f(CW0.09\fR \- earlier versions had performance problems with \&\f(CW\*(C`HTML::FormFu\*(C'\fR. .SS "Template::Alloy" .IX Subsection "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 \&\f(CW\*(C`HTML_FORMFU_TEMPLATE_ALLOY\*(C'\fR environment variable to a true value, or by passing \f(CW\*(C`TEMPLATE_ALLOY\*(C'\fR to \*(L"tt_args\*(R" in HTML::FormFu: .PP .Vb 4 \& tt_args: \& TEMPLATE_ALLOY: 1 \& COMPILE_DIR: /tmp \& COMPILE_PERL: 1 .Ve .PP Template::Alloy's caching is off by default. Switch it on by setting either \&\f(CW\*(C`COMPILE_EXT\*(C'\fR or \f(CW\*(C`COMPILE_DIR\*(C'\fR. If you're running under a persistent environment such as modperl or fastcgi, you should also set \f(CW\*(C`COMPILE_PERL\*(C'\fR to compile the cached templates down to perl code. .PP 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. .SS "HTML:FormFu::Preload" .IX Subsection "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: .PP .Vb 1 \& use HTML::FormFu::Preload; .Ve .SH "FAQs" .IX Header "FAQs" .SS "Force an element to always have a certain value" .IX Subsection "Force an element to always have a certain value" See the following: .PP \&\*(L"retain_default\*(R" in HTML::FormFu::Role::Element::Field, \&\*(L"force_default\*(R" in HTML::FormFu::Role::Element::Field .SH "AUTHORS" .IX Header "AUTHORS" Will Hawes \f(CW\*(C`wdhawes@gmail.com\*(C'\fR .PP Carl Franks \f(CW\*(C`cfranks@cpan.org\*(C'\fR .SH "COPYRIGHT" .IX Header "COPYRIGHT" This document is free, you can redistribute it and/or modify it under the same terms as Perl itself.