1HTML::FormFu::Manual::CUosoekrboCookn(t3r)ibuted Perl DoHcTuMmLe:n:tFaotrimoFnu::Manual::Cookbook(3)
2
3
4

NAME

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

VERSION

9       version 2.07
10

DESCRIPTION

12       Miscellaneous useful recipes for use with HTML::FormFu
13

GETTING STARTED

15       Some useful info for beginners.
16
17   Default search paths for config files
18       The current working directory ("cwd") (see "load_config_file" in
19       HTML::FormFu).
20
21       If you're using the "FormConfig" action attribute from
22       Catalyst::Controller::HTML::FormFu, forms should be saved in
23       "root/forms".  See "SYNOPSIS" in Catalyst::Controller::HTML::FormFu and
24       "config_file_path" in Catalyst::Controller::HTML::FormFu for further
25       details.
26
27   YAML
28       Most examples given in the HTML::FormFu documentation use YAML syntax.
29       You can use any configuration file type supported by Config::Any, but
30       this author's preferred format is YAML.
31
32       A form can be populated by a config file by calling "load_config_file"
33       in HTML::FormFu with the filename as an argument. The config file is
34       converted to a perl data-structure, and then passed to "populate" in
35       HTML::FormFu.
36
37       The config file must contain a hash-ref, with the keys corresponding to
38       form method-names, and the values being the method arguments. For
39       example, the following are equivalent:
40
41           ---
42           auto_fieldset: 1
43           elements:
44             - name: foo
45             - name: bar
46
47           # the above YAML is equivalent to the following perl code
48
49           $form->auto_fieldset(1);
50
51           $form->elements([
52               { name => 'foo' },
53               { name => 'bar' },
54           ]);
55
56       When writing your config file, remember that perl hashes are unordered
57       and cannot have multiple keys with the same name.
58
59       See "load_config_file" in HTML::FormFu and "populate" in HTML::FormFu
60       for more details.
61
62       See <http://www.yaml.org/spec/> for the YAML specification.
63

BUILDING A FORM

65   Quick single-file prototypes
66       You can run the following script to quickly view a form's markup -
67       replace the contents of the "__DATA__" section with your own YAML
68       config.
69
70           #!/usr/bin/perl
71               use warnings;
72           use HTML::FormFu;
73           use YAML::XS qw( LoadFile );
74
75           my $form = HTML::FormFu->new;
76           my $data = LoadFile(\*DATA);
77
78           $form->populate($data);
79
80           print $form;
81
82           __DATA__
83           ---
84           auto_fieldset: 1
85           elements:
86             - type: Text
87               name: foo
88
89   Unsupported HTML tags
90       You can use the HTML::FormFu::Element::Block element, and set the tag
91       to create any arbitrary pair of tags.
92
93           ---
94           elements:
95             - type: Block
96               tag: span
97               content_xml: "<b>Hi!</b>"
98
99       You can use "content" in HTML::FormFu::Element::Block, "content_xml" in
100       HTML::FormFu::Element::Block or "content_loc" in
101       HTML::FormFu::Element::Block to add any content you wish, or use
102       "element" in HTML::FormFu::Element::Block to add elements.
103

Application-wide default values

105       You can automatically set defaults using "default_args" in
106       HTML::FormFu, and if you set this in a Catalyst application config
107       file, it'll take effect throughout your entire application, for
108       example:
109
110           myapp.yml
111           ---
112           'Controller::HTML::FormFu':
113             constructor:
114               default_args:
115                 elements:
116                   Textarea:
117                     rows: 10
118

MODIFYING A FORM

120   Insert a new field before existing form fields
121       See "insert_before" in HTML::FormFu and "insert_after" in HTML::FormFu.
122
123           my $fieldset = $form->get_element({ type => 'Fieldset' });
124
125           $fieldset->insert_before(
126               $form->element(\%specs),
127               $form->get_field($name)
128           );
129
130       Another way to approach the problem is to use multiple config files,
131       and decide which to load at runtime:
132
133           # user_edit.yml
134           ---
135           elements:
136             - type: Text
137               name: email
138
139           # user_username.yml
140           ---
141           elements:
142             - type: Text
143               name: username
144
145            # user_register.yml
146            ---
147            load_config_file:
148             - user_username.yml
149             - user_edit.yml
150
151           # create a user edit form, with only the email field
152
153           $form->load_config_file( 'user_edit.yml' );
154
155           # create a user registration form with username and email fields
156
157           $form->load_config_file( 'user_register.yml' );
158
159   Form and Field attributes
160       You can add any arbitrary attributes to a form with "attributes" in
161       HTML::FormFu, or to any element with "attributes" in
162       HTML::FormFu::Element.
163
164           ---
165           attributes_xml:
166             onsubmit: "js_function()"
167           elements:
168             - type: Text
169               name: foo
170               attributes_xml:
171                 onchange: "js_function()"
172

FORM VALIDATION

174   Check valid dates
175       Use HTML::FormFu::Inflator::DateTime. When the inflator is processed,
176       it will try to create a DateTime object. An error will be returned if
177       the supplied values do not make a valid date.
178
179   Check valid URI / URLs
180       See HTML::FormFu::Element::URL or HTML::FormFu::Constraint::Regex.
181
182   Implement a custom constraint / validator
183       If HTML::FormFu::Constraint::Callback or
184       HTML::FormFu::Validator::Callback isn't sufficient for your needs, you
185       can create your own class that inherits from HTML::FormFu::Constraint
186       or HTML::FormFu::Validator, respectively.
187
188       It should implement a "validate_value" method, which returns true is
189       the value is valid, or false otherwise.
190
191           package My::Custom::Validator;
192           use Moose;
193           extends 'HTML::FormFu::Validator';
194
195           sub validate_value {
196             my ( $self, $value, $params ) = @_;
197
198             return 1 if value_is_valid( $value );
199
200             return;
201           }
202
203           1;
204
205       Then add your custom validator to the form:
206
207           ---
208           elements:
209             - type: Text
210               name: foo
211               validators:
212                 - '+My::Custom::Validator'
213
214   Constrain one form field based on the value of another
215       For example, you have a radiogroup and several text fields, with
216       different text fields being required depending on the value of the
217       radiogroup.
218
219       This is achieved using the "when" attribute of a constraint:
220
221           constraints:
222             - type: Length
223               min: 8
224               when:
225                 field: bar
226                 values: [ 1, 3, 5 ]
227
228       In the above example, the Length constraint is only processed when the
229       form field named "bar" has a value of either 1, 3 or 5.
230
231       You can also test for a negative condition using the "not" attribute:
232
233           constraints:
234             - type: Length
235               min: 8
236               when:
237                 field: bar
238                 values: [ 1, 3, 5 ]
239                 not: 1
240
241       Now the constraint will be processed only if the value of field "bar"
242       is NOT 1, 3 or 5.
243
244       Note: if you rely on the value of a checkbox for a when-restricted
245       contraint, you might want to consider setting "default_empty_value" for
246       that checkbox. Take a look at HTML::FormFu::Role::Element::Field to
247       learn more.
248
249       Please read HTML::FormFu::Constraint for further information.
250
251   Constrain one form field based on the return value of a callback
252       You can use the "when" attribute of a constraint also to decide using a
253       callback if the constraint should be applied.
254
255       For instance, the following (code) example shows a constraint being
256       applied only if the value of another field contains a pattern
257
258           my $apply_if_pattern = sub {
259               my $params = shift;
260               return 1 if $params->{other_field} =~ m/\A ice_cream \z/xms;
261               return 0;
262           };
263
264           $field->{constraints} = {
265               type    => 'Required',
266               when    => {
267                   callback    => $apply_if_pattern,
268               }
269           }
270
271       Please read HTML::FormFu::Constraint for further information.
272

HTML MARKUP

274   Indented HTML
275       Use HTML::FormFu::OutputProcessor::Indent:
276
277           ---
278           output_processors:
279             - Indent
280
281   Add a blank div (e.g. for AJAX purposes)
282       Simply add a Block element in the relevant place, it defaults to a
283       "DIV" tag.
284
285           ---
286           elements:
287             - type: Text
288               name: user
289
290             - type: Block
291               id: foo
292
293             - type: Text
294               name: email
295

DISPLAY

297   Custom error messages
298       If you want to display an error message due to an error in your own
299       code, such as a database check; something which isn't implemented as a
300       Constraint or Validator; you can use a Callback Constraint.
301
302       If you don't provide your own callback routine, the default callback
303       will always pass, regardless of user input.
304
305       You can take advantage of this by setting force_errors, to display its
306       error message when needed.
307
308       Example config:
309
310           ---
311           elements:
312             - type: Text
313             - name: email
314             - constraints:
315               type: Callback
316               message: 'Email address already in use'
317
318       Example usage:
319
320           if ( $@ =~ m/duplicate entry for key 'email'/i ) {
321
322               $form->get_field('email')
323                    ->get_constraint({ type => 'Callback' })
324                    ->force_errors(1);
325
326               $form->process;
327               # then redisplay the form as normal
328           }
329
330   Highlight required fields (or fields with certain types of constraint)
331       This can be achieved using the form's "auto_constraint_class" method:
332
333           $form->auto_constraint_class( 'constraint_%t' );
334
335       The container divs around any form field with a constraint will then
336       have extra CSS classes added, which indicate the type of constraint and
337       allow you to apply appropriate styling with CSS:
338
339           /* change background of labels for fields with a Required constraint */
340           fieldset .constraint_required label {
341               background: #f00;
342           }
343
344       This technique can also be used to add content before or after the
345       fields in question (note this will not work in older browsers with more
346       limited CSS support such as IE6):
347
348           /* add an asterisk at the end of the label for required fields */
349           fieldset .constraint_required label:after {
350               content: '*'
351           }
352
353   Add a popup hint to a field
354       Most display a tooltip when a user hovers their mouse pointer over an
355       HTML element with a "title" tag.  Aural browsers may try to turn the
356       content into speech.  You can take advantage of this behaviour to
357       provide a hint to the user about how to complete a form field.
358
359           elements:
360             - type: URL
361               name: url
362               label: Website
363               title: 'Must start with http:// or https://'
364
365       The above will provide a hint when the "url" field receives focus.  Or
366       you could provide the hint for the container tag around both field and
367       label:
368
369           elements:
370             - type: URL
371               name: url
372               label: Website
373               container_attributes:
374                   title: 'Must start with http:// or https://'
375
376   Display filtered values
377       If you have a Filter on a field, such as
378       HTML::FormFu::Filter::Whitespace to strip leading / trailing
379       whitespace, then if you redisplay the form the field is normally
380       populated with the value the user originally entered.
381
382       If you would like the field to contain the filtered value, use
383       "render_processed_value" in HTML::FormFu.
384
385   Multiple forms using Catalyst::Controller::HTML::FormFu
386       Sometimes you need to display multiple forms on a single page. If you
387       try to use FormConfig on several actions in a chain, or similar, they
388       all use "$c->stash->{form}" to store the form, hence you only get the
389       last form.
390
391       One way to work around such problems is to do a little of the work
392       yourself:
393
394       In this example we have a login_form that we want on every page
395
396           # root/forms/login.yml:
397           ---
398               indicator: username
399               elements:
400                   -
401                       type: Text
402                       name: username
403                       constraints:
404                           - Required
405           ...
406
407       We also have an edit-form
408
409           # root/forms/foo/edit.yml
410           ---
411               indicator: foo
412               elements:
413               -
414                   type: Text
415                   name: foo
416                   constraints:
417                       - Required
418           ...
419
420       In this example, we want the login form to appear on every page, so we
421       load this in the top-most auto action:
422
423           package MyApp::Controller::Root;
424
425           BEGIN { extends 'Catalyst::Controller::HTML::FormFu'; }
426
427           sub auto : Private {
428               my ($self, $c) = @_;
429
430               # We want to utilize a lot of the magic that the controller
431               # gives us, so therefore we call $self->form like this
432
433               my $login_form = $self->form;
434               $login_form->load_config_file('login.yml');
435
436               # Notice how we put it into another stash var, not 'form'
437               $c->stash->{login_form} = $login_form;
438               unless ($c->user_exists) {
439
440                   $login_form->process();
441
442                   if ($login_form->submitted_and_valid) {
443
444                       # Since we set indicator, we should only end up here if we
445                       # have a username in the form
446                       $c->authenticate({
447                           username => $login_form->param_value('username'),
448                           password => $login_form->param_value('password'),
449                       });
450                   }
451
452               }
453           }
454
455       Any other page that wants to load another form, can now do so freely:
456
457           package MyApp::Controller::Foo;
458
459           sub edit : Local FormConfig {
460               my ( $self, $c ) = @_;
461
462               my $form = $c->stash->{form};
463               if ($form->submitted_and_valid) {
464                   # Do whatever you want with it :p
465               }
466           }
467
468       In the view we now have two stash-variables:
469
470       In root/foo/edit.tt:
471           [% login_form %]
472           <h2>edit</h2>
473           [% form %]
474

ADVANCED CUSTOMISATION

476   Installing the TT templates
477       It only makes sense to use the template files if you plan on
478       customising them, as the default "string" render-method is faster.
479
480       As of "HTML::FormFu v1.00", TT is no longer listed a required
481       prerequisite - so you'll need to install it manually if you with to use
482       the template files.
483
484       If you're using the Catalyst web framework, install
485       Catalyst::Controller::HTML::FormFu and run the following command:
486
487           $ script/myapp_create.pl HTML::FormFu
488
489       This will create a directory, "root/formfu", containing the
490       HTML::FormFu template files.
491
492       If you extend Catalyst::Controller::HTML::FormFu and you don't set
493       HTML::FormFu's INCLUDE_PATH yourself, it will automatically be set to
494       "root/formfu" if that directory exists.
495
496       If you're not using Catalyst, you can create the template files by
497       running the following command:
498
499             $ html_formfu_deploy.pl <target-directory>
500
501       Take note that if you choose to customise your own copy of
502       HTML::FormFu's template files, you'll need to keep track of the
503       "Changes" file, when updating HTML::FormFu, so that you can update your
504       own templates if the core templates are updated.
505

PERFORMANCE

507   Catalyst::Plugin::StackTrace
508       If you're using Catalyst::Plugin::StackTrace, make sure you're using at
509       least version 0.09 - earlier versions had performance problems with
510       "HTML::FormFu".
511
512   Template::Alloy
513       You can also use Template::Alloy instead of Template::Toolkit, it's
514       mostly compatible, and in many cases provides a reasonable speed
515       increase. You can do this either by setting the
516       "HTML_FORMFU_TEMPLATE_ALLOY" environment variable to a true value, or
517       by passing "TEMPLATE_ALLOY" to "tt_args" in HTML::FormFu:
518
519           tt_args:
520             TEMPLATE_ALLOY: 1
521             COMPILE_DIR: /tmp
522             COMPILE_PERL: 1
523
524       Template::Alloy's caching is off by default. Switch it on by setting
525       either "COMPILE_EXT" or "COMPILE_DIR". If you're running under a
526       persistent environment such as modperl or fastcgi, you should also set
527       "COMPILE_PERL" to compile the cached templates down to perl code.
528
529       Of cource, if you wish you can still use Template::Toolkit to process
530       your own application templates, letting Template::Alloy process just
531       the HTML::FormFu templates.
532
533   HTML:FormFu::Preload
534       To reduce the runtime for each form that uses a previously unused
535       element or processor - at the expense of greater memory usage - you can
536       preload all FormFu modules - this is only recommended for persistent
537       environments such as modperl or fastcgi:
538
539           use HTML::FormFu::Preload;
540

FAQs

542   Force an element to always have a certain value
543       See the following:
544
545       "retain_default" in HTML::FormFu::Role::Element::Field, "force_default"
546       in HTML::FormFu::Role::Element::Field
547

AUTHORS

549       Will Hawes "wdhawes@gmail.com"
550
551       Carl Franks "cfranks@cpan.org"
552
554       This document is free, you can redistribute it and/or modify it under
555       the same terms as Perl itself.
556

AUTHOR

558       Carl Franks <cpan@fireartist.com>
559
561       This software is copyright (c) 2018 by Carl Franks.
562
563       This is free software; you can redistribute it and/or modify it under
564       the same terms as the Perl 5 programming language system itself.
565
566
567
568perl v5.30.1                      2020-01-30 HTML::FormFu::Manual::Cookbook(3)
Impressum