File Coverage

blib/lib/HTML/FormBuilder.pm
Criterion Covered Total %
statement 177 187 94.6
branch 62 78 79.4
condition 23 37 62.1
subroutine 21 22 95.4
pod 9 9 100.0
total 292 333 87.6


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