File Coverage

blib/lib/HTML/FormBuilder.pm
Criterion Covered Total %
statement 177 187 94.6
branch 62 78 79.4
condition 24 37 64.8
subroutine 21 22 95.4
pod 9 9 100.0
total 293 333 87.9


line stmt bran cond sub pod time code
1              
2             use strict;
3 7     7   436342 use warnings;
  7         77  
  7         208  
4 7     7   37 use 5.008_005;
  7         13  
  7         159  
5 7     7   121 our $VERSION = '0.13';
  7         44  
6              
7             use Carp;
8 7     7   44 use HTML::FormBuilder::FieldSet;
  7         17  
  7         459  
9 7     7   3033 use String::Random ();
  7         27  
  7         257  
10 7     7   3772 use Moo;
  7         29214  
  7         213  
11 7     7   48 use namespace::clean;
  7         17  
  7         38  
12 7     7   2285 use HTML::Entities;
  7         17  
  7         42  
13 7     7   4920 extends qw(HTML::FormBuilder::Base);
  7         34822  
  7         16810  
14              
15             has data => (
16             is => 'ro',
17             isa => sub {
18             my $data = shift;
19             croak('data should be a hashref') unless ref($data) eq 'HASH';
20             croak("Form must be given an id when instantiating a HTML::FormBuilder->new object in $0.") if !defined $data->{'id'};
21             },
22             default => sub {
23             {};
24             },
25             );
26              
27             has fieldsets => (
28             is => 'rw',
29             isa => sub {
30             my $fieldsets = shift;
31             return 1 unless $fieldsets;
32             croak('fieldsets should be an arrayref')
33             unless ref($fieldsets) eq 'ARRAY';
34             },
35             default => sub {
36             [];
37             },
38             );
39              
40             has after_form => (
41             is => 'rw',
42             isa => sub {
43             return !ref($_[0]);
44             });
45              
46             has csrftoken => (is => 'ro');
47              
48             my (undef, @args) = @_;
49             my %args = (@args % 2) ? %{$args[0]} : @args;
50 27     27 1 36158  
51 27 50       144 # set default class
  0         0  
52             if ($args{classes}) {
53             $args{classes} = {%{$HTML::FormBuilder::Base::CLASSES}, %{$args{classes}}};
54 27 100       80 } else {
55 16         30 $args{classes} = {%{$HTML::FormBuilder::Base::CLASSES}};
  16         68  
  16         176  
56             }
57 11         19  
  11         120  
58             if (($args{csrftoken} // '') eq '1') {
59             $args{csrftoken} = String::Random::random_regex('[a-zA-Z0-9]{16}');
60 27 100 100     176 }
61 2         9  
62             $args{data}{method} ||= 'get';
63             $args{data}{method} = 'get' if $args{data}{method} ne 'post';
64 27   100     860 return \%args;
65 27 100       91 }
66 27         514  
67             #####################################################################
68             # Usage : Add a new fieldset to the form
69             # Purpose : Allow the form object to carry more than 1 fieldsets
70             # Returns : Fieldset object
71             # Parameters : Hash reference with keys in <fieldsets> supported attributes
72             # Comments : Fieldset works like a table, which allow one form to
73             # have more than 1 fieldset. Each Fieldset has its own
74             # input fields.
75             # See Also :
76             #####################################################################
77             my $self = shift;
78             my $_args = shift;
79              
80 26     26 1 3840 #check if the $args is a ref HASH
81 26         39 croak("Parameters must in HASH reference in $0.")
82             if (ref $_args ne 'HASH');
83              
84 26 50       87 my $fieldset = HTML::FormBuilder::FieldSet->new(
85             data => $_args,
86             classes => $self->classes,
87 26         507 localize => $self->localize
88             );
89              
90             push @{$self->{fieldsets}}, $fieldset;
91              
92             return $fieldset;
93 26         182 }
  26         90  
94              
95 26         136 #####################################################################
96             # Usage : Add a new input fields to the fieldset
97             # Purpose : Check is the fieldset is created, and if is created
98             # add the input field into the fieldset
99             # Returns :
100             # Parameters : Hash reference with keys
101             # 'label' => $ref_hash
102             # 'input' => $ref_hash
103             # 'error' => $ref_hash
104             # 'comment' => $ref_hash
105             # Comments : check pod below to understand how to create different input fields
106             # See Also :
107             #####################################################################
108             my $self = shift;
109             my $fieldset_index = shift;
110             my $_args = shift;
111              
112 2     2 1 845 #check if the fieldset_index is number
113 2         5 croak("The fieldset_index should be a number")
114 2         3 unless ($fieldset_index =~ /^\d+$/);
115              
116             #check if the fieldset array is already created
117 2 100       31 croak("The fieldset does not exist in $0. form_id[$self->{data}{'id'}]")
118             if ($fieldset_index > $#{$self->{fieldsets}});
119              
120             my $fieldset = $self->{fieldsets}[$fieldset_index];
121             return $fieldset->add_field($_args);
122 1 50       3  
  1         19  
123             }
124 0         0  
125 0         0 #####################################################################
126             # Usage : generate the form
127             # Purpose : check and parse the parameters and generate the form
128             # properly
129             # Returns : form HTML
130             # Parameters : Fieldset index that would like to print, null to print all
131             # Comments :
132             # See Also :
133             # TODO : seems the parameter fieldset index useless.
134             #####################################################################
135             my $self = shift;
136             my $print_fieldset_index = shift;
137              
138             # build the fieldset, if $print_fieldset_index is specifed then
139             # we only generate that praticular fieldset with that index
140 16     16 1 2139 my @fieldsets;
141 16         27 if (defined $print_fieldset_index) {
142             push @fieldsets, $self->{'fieldsets'}[$print_fieldset_index];
143             } else {
144             @fieldsets = @{$self->{'fieldsets'}};
145 16         27 }
146 16 50       48  
147 0         0 my %grouped_fieldset;
148              
149 16         25 # build the form fieldset
  16         42  
150             foreach my $fieldset (@fieldsets) {
151             my ($fieldset_group, $fieldset_html) = $fieldset->build();
152 16         31 push @{$grouped_fieldset{$fieldset_group}}, $fieldset_html;
153             }
154              
155 16         35 my $fieldsets_html = '';
156 18         65 foreach my $fieldset_group (sort keys %grouped_fieldset) {
157 18         32 if ($fieldset_group ne 'no-group') {
  18         68  
158             $fieldsets_html .= qq[<div id="$fieldset_group" class="$self->{classes}{fieldset_group}">];
159             }
160 16         33  
161 16         46 foreach my $fieldset_html (@{$grouped_fieldset{$fieldset_group}}) {
162 14 100       60 $fieldsets_html .= $fieldset_html;
163 1         4 }
164              
165             if ($fieldset_group ne 'no-group') {
166 14         24 $fieldsets_html .= '</div>';
  14         31  
167 18         78 }
168             }
169              
170 14 100       43 if ($self->csrftoken) {
171 1         3 $fieldsets_html .= sprintf qq(<input type="hidden" name="csrftoken" value="%s"/>), $self->csrftoken;
172             }
173              
174             my $html = $self->_build_element_and_attributes('form', $self->{data}, $fieldsets_html);
175 16 100       95  
176 2         11 if ($self->after_form) {
177             $html .= $self->after_form;
178             }
179 16         74  
180             return $html;
181 16 100       375 }
182 1         22  
183             #
184             # This builds a bare-bone version of the form with all inputs hidden and only
185 16         205 # displays a confirmation button. It can be used for when we'd like to ask
186             # the Client to confirm what has been entered before processing.
187             #
188             # This output currently only outputs text or hidden fields, and ignores the
189             # rest. Extra functionality would need to be added to handle any type of form.
190             #
191             my $self = shift;
192             my @inputs;
193              
194             # get all inputs that are to be output as hidden
195             foreach my $fieldset (@{$self->{'fieldsets'}}) {
196             INPUT:
197 3     3 1 623 foreach my $input_field (@{$fieldset->{'fields'}}) {
198 3         7 my $data = $input_field->{data};
199             next INPUT if (not defined $data->{'input'});
200              
201 3         14 push @inputs, @{$data->{'input'}};
  3         14  
202              
203 2         4 }
  2         6  
204 2         6 }
205 2 50       7  
206             my $html = '';
207 2         5  
  2         7  
208             foreach my $input (@inputs) {
209             next if ($input->{'type'} and $input->{'type'} eq 'submit');
210             my $n = $input->{'name'} || '';
211             my $val = $self->get_field_value($input->{'id'}) || '';
212 3         7 $html .= qq{<input type="hidden" name="$n" value="$val"/>};
213             }
214 3         8  
215 2 50 33     15 if ($self->csrftoken) {
216 2   50     8 $html .= sprintf qq(<input type="hidden" name="csrftoken" value="%s"/>), $self->csrftoken;
217 2   50     10 }
218 2         15  
219             $html .= '<input type="hidden" name="process" value="1"/>';
220             $html .= _link_button({
221 3 100       34 value => $self->_localize('Back'),
222 1         13 class => $self->{classes}{backbutton},
223             href => 'javascript:history.go(-1)',
224             });
225 3         10 $html .= ' <span class="button"><button id="submit" class="button" type="submit">' . $self->_localize('Confirm') . '</button></span>';
226             $html = $self->_build_element_and_attributes('form', $self->{data}, $html);
227              
228             return $html;
229 3         48 }
230              
231 3         16 ################################################################################
232 3         16 # Usage : $form_obj->set_field_value('input_element_id', 'foo');
233             # Purpose : Set input value based on input element id
234 3         17 # Returns : none
235             # Parameters : $field_id: Input element ID
236             # $field_value: Value (text)
237             # Comments : Public
238             # See Also : get_field_value
239             ################################################################################
240             my $self = shift;
241             my $field_id = shift;
242             my $field_value = shift;
243             return unless $field_id;
244              
245             my $input_field = $self->_get_input_field($field_id);
246             return unless $input_field;
247 62     62 1 201  
248 62         96 my $data = $input_field->{data};
249 62         88 my $inputs = $data->{input};
250 62 50       122  
251             map {
252 62         117 if ($_->{'id'} and $_->{'id'} eq $field_id) {
253 62 100       121 if (eval { $_->can('value') }) {
254             # for select box
255 60         87 $_->value($field_value);
256 60         80 } elsif ($_->{'type'} =~ /(?:text|textarea|password|hidden|file)/i) {
257             $_->{'value'} = HTML::Entities::encode_entities($field_value // '');
258             } elsif ($_->{'type'} eq 'checkbox') {
259 86 100 66     390 # if value not set during $fieldset->add_field(), default to browser default value for checkbox: 'on'
260 60 100       82 my $checkbox_value = $_->{'value'} // 'on';
  60 100       506  
    50          
261             $_->{'checked'} = 'checked' if ($field_value eq $checkbox_value);
262 13         36 }
263             }
264 36   50     125 } @{$inputs};
265             return;
266             }
267 11   50     31  
268 11 50       102 ################################################################################
269             # Usage : $form_obj->get_field_value('input_element_id');
270             # Purpose : Get input value based on input element id
271 60         78 # Returns : text (Input value) / undef
  60         103  
272 60         682 # Parameters : $field_id: Input element ID
273             # Comments : Public
274             # See Also : set_field_value
275             ################################################################################
276             my $self = shift;
277             my $field_id = shift;
278              
279             my $input_field = $self->_get_input_field($field_id);
280             return unless $input_field;
281              
282             my $inputs = $input_field->{data}{input};
283             foreach my $input (@$inputs) {
284 88     88 1 693 if ($input->{'id'} and $input->{'id'} eq $field_id) {
285 88         122 if (eval { $input->can('value') }) {
286             return $input->value;
287 88         179 }
288 88 100       193 return unless $input->{type};
289              
290 86         121 if ($input->{type} =~ /(?:text|textarea|password|hidden|file)/i) {
291 86         127 return HTML::Entities::decode_entities($input->{value} // '');
292 103 100 66     323 } elsif ($input->{type} eq 'checkbox' && $input->{checked} && $input->{checked} eq 'checked') {
293 86 100       123 # if value not set during $fieldset->add_field(), default to browser default value for checkbox: 'on'
  86         490  
294 13         49 return ($input->{value} // 'on');
295             }
296 73 50       184 }
297             }
298 73 100 66     353 return;
    100 66        
299 58   50     405 }
300              
301             ################################################################################
302 11   50     56 # Usage : 1. $form_obj->set_field_error_message('input_element_id', 'some error');
303             # 2. $form_obj->set_field_error_message('error_element_id', 'some error');
304             # Purpose : Set error message based on input element id or error element id
305             # Returns : none
306 4         19 # Parameters : $field_id: Field ID (input or error)
307             # $error_msg: Error message text
308             # Comments : Public
309             # See Also : get_field_error_message
310             ################################################################################
311             my $self = shift;
312             my $field_id = shift;
313             my $error_msg = shift;
314              
315             my $input_field = $self->_get_input_field($field_id);
316             if ($input_field) {
317             $input_field->{data}{'error'}{'text'} = $error_msg;
318             return;
319             }
320 12     12 1 23  
321 12         18 my $error_field = $self->_get_error_field($field_id);
322 12         17 if ($error_field) {
323             $error_field->{data}{'error'}{'text'} = $error_msg;
324 12         26 return;
325 12 100       31 }
326 11         23 return;
327 11         23 }
328              
329             ################################################################################
330 1         3 # Usage : 1. $form_obj->get_field_error_message('input_element_id');
331 1 50       4 # 2. $form_obj->get_field_error_message('error_element_id');
332 1         2 # Purpose : Get error message based on input element id or error element id
333 1         3 # Returns : text (Error message)
334             # Parameters : $field_id: Field ID (input or error)
335 0         0 # Comments : Public
336             # See Also : set_field_error_message
337             ################################################################################
338             my $self = shift;
339             my $field_id = shift;
340              
341             my $input_field = $self->_get_input_field($field_id);
342             return $input_field->{data}{'error'}{'text'} if $input_field;
343              
344             my $error_field = $self->_get_error_field($field_id);
345             return $error_field->{data}{'error'}{'text'} if $error_field;
346              
347             return;
348 8     8 1 529 }
349 8         15  
350             #####################################################################
351 8         19 # Usage : $self->_get_input_field('amount');
352 8 100       47 # Purpose : Get the element based on input field id
353             # Returns : Element contains input field
354 1         3 # Parameters : $field_id: Field ID
355 1 50       7 # Comments : Private
356             # See Also :
357 0         0 #####################################################################
358             my $self = shift;
359             my $field_id = shift;
360              
361             return unless $field_id;
362             foreach my $fieldset (@{$self->{'fieldsets'}}) {
363             foreach my $input_field (@{$fieldset->{'fields'}}) {
364             my $inputs = $input_field->{data}{input};
365             foreach my $sub_input_field (@$inputs) {
366             if ( $sub_input_field->{id}
367             and $sub_input_field->{id} eq $field_id)
368             {
369 170     170   252 return $input_field;
370 170         224 }
371             }
372 170 100       295 }
373 169         221 }
  169         345  
374 169         216  
  169         285  
375 757         1080 return;
376 757         1103 }
377 689 100 66     2052  
378             #####################################################################
379             # Usage : $self->_get_error_field('error_amount');
380 164         347 # Purpose : Get the element based on error field id
381             # Returns : Element contains error field
382             # Parameters : $error_id: Error ID
383             # Comments : Private
384             # See Also :
385             #####################################################################
386 5         11 my $self = shift;
387             my $error_id = shift;
388              
389             return unless $error_id;
390              
391             #build the form fieldset
392             foreach my $fieldset (@{$self->{'fieldsets'}}) {
393             foreach my $input_field (@{$fieldset->{'fields'}}) {
394             if ( $input_field->{data}{error}{id}
395             and $input_field->{data}{error}{id} eq $error_id)
396             {
397             return $input_field;
398 2     2   4 }
399 2         3 }
400             }
401 2 50       5 return;
402             }
403              
404 2         3 #####################################################################
  2         5  
405 2         3 # Usage : $self->_link_button({value => 'back', class => 'backbutton', href => '})
  2         4  
406 16 100 100     46 # Purpose : create link button html
407             # Returns : HTML
408             # Parameters : {value, class, href}
409 2         5 # Comments :
410             # See Also :
411             #####################################################################
412             my $args = shift;
413 0         0  
414             my $myclass = $args->{'class'} ? 'button ' . $args->{'class'} : 'button';
415              
416             my $myid = $args->{'id'} ? 'id="' . $args->{'id'} . '"' : '';
417             my $myspanid = $args->{'id'} ? 'id="span_' . $args->{'id'} . '"' : '';
418              
419             return qq{<a class="$myclass" href="$args->{href}" $myid><span class="$myclass" $myspanid>$args->{value}</span></a>};
420             }
421              
422             #####################################################################
423             # Usage : $self->_wrap_fieldset($fieldset_html)
424             # Purpose : wrap fieldset html by template
425 3     3   13 # Returns : HTML
426             # Comments :
427 3 50       20 # See Also :
428             #####################################################################
429 3 50       11 my ($self, $fieldset_html) = @_;
430 3 50       17 my $fieldset_template = <<EOF;
431             <div class="rbox form">
432 3         22 <div class="rbox-wrap">
433             $fieldset_html
434             <span class="tl">&nbsp;</span><span class="tr">&nbsp;</span><span class="bl">&nbsp;</span><span class="br">&nbsp;</span>
435             </div>
436             </div>
437             EOF
438              
439             return $fieldset_template;
440             }
441              
442             1;
443 0     0      
444 0           =head1 NAME
445              
446             HTML::FormBuilder - A Multi-part HTML form
447              
448             =head1 SYNOPSIS
449              
450             #define a form
451             my $form = HTML::FormBuilder->new(
452             data =>{id => 'formid',
453 0           class => 'formclass'},
454             classes => {row => 'rowdev'})
455              
456             #create fieldset
457             my $fieldset = $form->add_fieldset({id => 'fieldset1});
458              
459             #add field
460             $fieldset->add_field({input => {name => 'name', type => 'text', value => 'Join'}});
461              
462             #set field value
463             $form->set_field_value('name', 'Omid');
464              
465             #output the form
466             print $form->build;
467              
468             =head1 DESCRIPTION
469              
470             Object-oriented module for displaying an HTML form.
471              
472             =head2 Overview of Form's HTML structure
473              
474             The root of the structure is the <form> element and follow by multiple <fieldset> elements.
475              
476             In each <fieldset>, you can create rows which contain label, different input types, error message and comment <p> element.
477              
478             Please refer to L</"A full sample result">
479              
480             =head1 Attributes
481              
482             =head2 data
483              
484             The form attributes. It should be a hashref.
485              
486             =head2 classes
487              
488             The form classes. It should be a hashref. You can customize the form's layout by the classes.
489             The class names used are:
490              
491             fieldset_group
492             no_stack_field_parent
493             row_padding
494             fieldset_footer
495             comment
496             row
497             extra_tooltip_container
498             backbutton
499             required_asterisk
500             inputtrailing
501             label_column
502             input_column
503             hide_mobile
504              
505             =head2 localize
506              
507             The subroutine ref which can be called when translate something like 'Confirm'. The default value is no translating.
508              
509             =head2 fieldsets
510              
511             The fieldsets the form have.
512              
513             =head1 Methods
514              
515             =head2 new
516              
517             my $form = HTML::FormBuilder->new(
518             data =>{id => 'formid',
519             class => 'formclass'},
520             classes => {row => 'rowdev'})
521              
522             The id is required for the form.
523              
524             =head2 add_fieldset
525              
526             my $fieldset = $form->add_fieldset({id => 'fieldset1});
527              
528             the parameter is the fieldset attributes.
529             It will return the fielset object.
530              
531             =head2 add_field
532              
533             $form->add_field(0, {input => {name => 'name', type => 'text', value => 'Join'}});
534              
535             The parameter is the fieldset index to which you want to add the field and the field attributes.
536              
537             =head2 build
538              
539             print $form->build;
540              
541             the data in the $form will be changed when build the form. So you cannot get the same result if you call build twice.
542              
543             =head2 BUILDARGS
544              
545             =head2 build_confirmation_button_with_all_inputs_hidden
546              
547             =head2 csrftoken
548              
549             =head2 get_field_error_message
550              
551             =head2 get_field_value
552              
553             =head2 set_field_error_message
554              
555             =head2 set_field_value
556              
557             =head1 Cookbook
558              
559             =head2 a full sample
560              
561             # Before create a form, create a classes hash for the form
562             my $classes = {comment => 'comment', 'input_column' => 'column'};
563             # And maybe you need a localize function to translate something
564             my $localize = sub {i18n(shift)};
565              
566             # First, create the Form object. The keys in the HASH reference is the attributes of the form
567             $form_attributes => {'id' => 'id_of_the_form',
568             'name' => 'name_of_the_form',
569             'method' => 'post', # or get
570             'action' => 'page_to_submit',
571             'header' => 'My Form',
572             'localize' => $localize,
573             'classes' => $classes,
574             }; #header of the form
575             my $form = HTML::FormBuilder->new(data => $form_attributes, classes => $classes, localize => $localize);
576              
577             #Then create fieldset, the form is allow to have more than 1 fieldset
578             #The keys in the HASH reference is the attributes of the fieldset
579              
580             $fieldset_attributes => {'id' => 'id_of_the_fieldset',
581             'name' => 'name_of_the_fieldset',
582             'class' => 'myclass',
583             'header' => 'User details', #header of the fieldset
584             'comment' => 'please fill in', #message at the top of the fieldset
585             'footer' => '* - required',}; #message at the bottom of the fieldset
586             };
587             my $fieldset = $form->add_fieldset($fieldset_attributes);
588              
589             ####################################
590             #Create the input fields.
591             ####################################
592             #When creating an input fields, there are 4 supported keys.
593             #The keys are label, input, error, comment
594             # Label define the title of the input field
595             # Input define and create the actual input type
596             # In input fields, you can defined a key 'heading', which create a text before the input is displayed,
597             # however, if the input type is radio the text is behind the radio box
598             # Error message that go together with the input field when fail in validation
599             # Comment is the message added to explain the input field.
600              
601             ####################################
602             ###Creating a input text
603             ####################################
604              
605             my $input_text = {'label' => {'text' => 'Register Name', for => 'name'},
606             'input' => {'type' => 'text', 'value' => 'John', 'id' => 'name', 'name' => 'name', 'maxlength' => '22'},
607             'error' => { 'id' => 'error_name' ,'text' => 'Name must be in alphanumeric', 'class' => 'errorfield hidden'},
608             'comment' => {'text' => 'Please tell us your name'}};
609              
610             ####################################
611             ###Creating a select option
612             ####################################
613             my @options;
614             push @options, {'value' => 'Mr', 'text' => 'Mr'};
615             push @options, {'value' => 'Mrs', 'text' => 'Mrs'};
616              
617             my $input_select = {'label' => {'text' => 'Title', for => 'mrms'},
618             'input' => {'type' => 'select', 'id' => 'mrms', 'name' => 'mrms', 'options' => \@options},
619             'error' => {'text' => 'Please select a title', 'class' => 'errorfield hidden'}};
620              
621              
622             ####################################
623             ###Creating a hidden value
624             ####################################
625             my $input_hidden = {'input' => {'type' => 'hidden', 'value' => 'John', 'id' => 'name', 'name' => 'name'}};
626              
627             ####################################
628             ###Creating a submit button
629             ####################################
630             my $input_submit_button = {'input' => {'type' => 'submit', 'value' => 'Submit Form', 'id' => 'submit', 'name' => 'submit'}};
631              
632             ###NOTES###
633             Basically, you just need to change the type to the input type that you want and generate parameters with the input type's attributes
634              
635             ###########################################################
636             ###Having more than 1 input field in a single row
637             ###########################################################
638             my $input_select_dobdd = {'type' => 'select', 'id' => 'dobdd', 'name' => 'dobdd', 'options' => \@ddoptions};
639             my $input_select_dobmm = {'type' => 'select', 'id' => 'dobmm', 'name' => 'dobmm', 'options' => \@mmoptions};
640             my $input_select_dobyy = {'type' => 'select', 'id' => 'dobyy', 'name' => 'dobyy', 'options' => \@yyoptions};
641             my $input_select = {'label' => {'text' => 'Birthday', for => 'dobdd'},
642             'input' => [$input_select_dobdd, $input_select_dobmm, $input_select_dobyy],
643             'error' => {'text' => 'Invalid date.'}};
644              
645             #Then we add the input field into the Fieldset
646             #You can add using index of the fieldset
647             $fieldset->add_field($input_text);
648             $fieldset->add_field($input_select);
649             $fieldset->add_field($input_submit_button);
650              
651             ###########################################################
652             ### Field value accessors
653             ###########################################################
654             $form->set_field_value('name', 'Omid');
655             $form->get_field_value('name'); # Returns 'Omid'
656              
657             ###########################################################
658             ### Error message accessors
659             ###########################################################
660             $form->set_field_error_message('name', 'Your name is not good :)');
661             # or
662             $form->set_field_error_message('error_name', 'Your name is not good :)');
663              
664             $form->get_field_error_message('name'); # Return 'Your name is not good :)'
665             # or
666             $form->get_field_error_message('error_name'); # Return 'Your name is not good :)'
667              
668             #Finally, we output the form
669             print $form->build();
670              
671              
672             =head2 A full sample result
673              
674             <form id="onlineIDForm" method="post" action="">
675             <fieldset id="fieldset_one" name="fieldset_one" class="formclass">
676             <div>
677             <label for="name">Register Name</label>
678             <em>:</em>
679             <input type="text" value="John" id="name" name="name">
680             <p id = "error_name" class="errorfield hidden">Name must be in alphanumeric</p>
681             <p>Please tell us your name</p>
682             </div>
683             <div>
684             <label for="mrms">Title</label>
685             <em>:</em>
686             <select id="mrms" name="mrms">
687             <option value="Mr">Mr</option>
688             <option value="Mrs">Mrs</option>
689             </select>
690             <p class="errorfield hidden">Please select a title</p>
691             </div>
692             <div>
693             <label for="dob">Birthday</label>
694             <em>:</em>
695             <select id="dobdd" name="dobdd">
696             <option value="1">1</option>
697             <option value="2">2</option>
698             </select>
699             <select id="dobmm" name="dobmm">
700             <option value="1">Jan</option>
701             <option value="2">Feb</option>
702             </select>
703             <select id="dobyy" name="dobyy">
704             <option value="1980">1980</option>
705             <option value="1981">1981</option>
706             </select>
707             <p class="errorfield hidden">Invalid date</p>
708             </div>
709             <div>
710             <input type="submit" value="Submit Form" id="submit" name="submit">
711             </div>
712             </fieldset>
713             </form>
714              
715             =head2 How to create a form with validation
716              
717             Please refer to <HTML::FormBuilder::Validation>
718              
719             =head2 CROSS SITE REQUEST FORGERY PROTECTION
720              
721             read <HTML::FormBuilder::Validation> for more details
722              
723             =head1 AUTHOR
724              
725             Chylli L<mailto:chylli@binary.com>
726              
727             =head1 CONTRIBUTOR
728              
729             Fayland Lam L<mailto:fayland@binary.com>
730              
731             Tee Shuwn Yuan L<mailto:shuwnyuan@binary.com>
732              
733             =head1 COPYRIGHT AND LICENSE
734              
735             =cut
736