1HTML::FormFu::Manual::CUosoekrboCookn(t3r)ibuted Perl DoHcTuMmLe:n:tFaotrimoFnu::Manual::Cookbook(3)
2
3
4
6 HTML::FormFu::Manual::Cookbook - Cooking with HTML::FormFu
7
9 version 2.07
10
12 Miscellaneous useful recipes for use with HTML::FormFu
13
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
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
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
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
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
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
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
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
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
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
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
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.32.0 2020-07-28 HTML::FormFu::Manual::Cookbook(3)