{"id":427,"date":"2013-08-23T19:39:26","date_gmt":"2013-08-24T00:39:26","guid":{"rendered":"http:\/\/www.aibistin.com\/?p=427"},"modified":"2013-08-25T21:10:09","modified_gmt":"2013-08-26T02:10:09","slug":"creating-a-repeatable-address-form-with-htmlformhandler","status":"publish","type":"post","link":"https:\/\/www.aibistin.com\/?p=427","title":{"rendered":"Creating a Repeatable Address Form with HTML::FormHandler"},"content":{"rendered":"<p class=\"important\">\nThis is a summary of how I created a repeatable Address Form Module, <a class=\"vital-link\"  href=\"https:\/\/github.com\/aibistin\/Mover-Form-Travel-Matrix\" title=\"Mover::Form::Travel::Matrix\"  target=\"_blank\">Mover::Form::Travel::Matrix<\/a>, using HTML::FormHandler.<\/p>\n<p><p>\nAs part of my <a href=\"https:\/\/github.com\/aibistin\/TravelTime\" title=\"Travel Time Application\" target=\"_blank\">TravelTime Application<\/a> project I needed to create a form to enter multiple location addresses. I could construct the form manually using Template Toolkit, but I would still need to write my own validation and JavaScript to implement the multiple form requirement.<br \/>\nI could have used <a hef=\"https:\/\/metacpan.org\/module\/CFRANKS\/HTML-FormFu-0.09010\/lib\/HTML\/FormFu.pm\" title=\"FormFu\"> HTML::FormFU<\/a> I have used this previously(much to my regret) to build more complex forms. Not that HTML::FormFu isn&#8217;t useful. Once it is mastered it can be a great tool for building many types of complex forms. For me, I found that the learning curve was much too steep and the documentation was dispersed widely amongst many modules. I am sure that this has been improved in recent times, but I really don&#8217;t want to go back to pouring through reams of docs for this  project.<br \/>\nSo I continued on my quest to use another behemoth of CPAN complexity just to make my life more difficult. I had wanted an excuse to experiment with <a href=\"https:\/\/metacpan.org\/module\/HTML::FormHandler\" title=\"FormHandler\"  target=\"_blank\">HTML::Formhandler<\/a> and this seemed like a good time to do this.  The documentation for this makes War And Peace seem like a side note on a shopping list. It must have taken longer to create than the Bible and hopefully will be less contentious. Seemingly it is the work of one developer by the name of Gerda Shank who must have locked herself away in a cave for a millennium to give the Pearl world this form framework.<br \/>\nWhat I like about HTML::FormHandler is that it seems much more Moose Like and intuitive to anybody who has worked with Moose. It seems very simple at first, however to get the best out of this, the learning curve is steep and requires time. So, say goodbye to family and social life while you get familiar with HTML::FormHandler.\n<\/p>\n<p class=\"code-heading\">FormHandler Forms<\/p>\n<p><span class=\"code-description\">Mover::Form::Field::Address<\/span><\/p>\n<p>Before I make my repeatable address form, I created a form element for any US address using a FormHandler Moose Role. This is one of the many useful things about HTML::Formhandler. You can create many building blocks which can be used again and again. Here is the module on github <tad-larger> <a class=\"vital-link\" href=\"https:\/\/github.com\/aibistin\/Mover-Form-Field-Address\" title=\"Mover::Form::Field::Address\"  target=\"_blank\">Mover::Form::Field::Address<\/a><br \/>\n<\/tad-larger>\n<\/p>\n<pre class=\"brush: css; auto-links: false; collapse: false; first-line: 1; gutter: true; light: false; pad-line-numbers: false; smart-tabs: false; tab-size: 4; title: Excerpt from Address.pm; toolbar: true; notranslate\" title=\"Excerpt from Address.pm\">\r\n.....\r\n\r\nuse HTML::FormHandler::Types qw\/Zip Trim Collapse\/;\r\n\r\nhas_field 'address_1' =&gt; (\r\n    is      =&gt; 'rw', \r\n    isa     =&gt; Collapse, \r\n    required =&gt; 0,\r\n    message  =&gt; {\r\n        required =&gt; 'You must enter a street address!'\r\n    }\r\n);\r\nhas_field 'address_2' =&gt; (is =&gt; 'rw', isa =&gt; Collapse);\r\nhas_field 'city' =&gt; (is =&gt; 'rw', isa =&gt; Collapse);\r\nhas_field 'state' =&gt; ( type =&gt; 'Select', options_method =&gt; \\&amp;_options_state );\r\nhas_field 'country' =&gt; (is =&gt; 'rw', isa =&gt; Collapse);\r\n#------ Create Zip Field Type\r\nhas_field 'zip' =&gt; ( is =&gt; 'rw',  isa =&gt; Zip);\r\n#------------------------------------------------------------------------------\r\n=head2 options_state\r\n  Builds the Options for US states. (NY New York,  AL Alabama etc).\r\n  Note: It does not include &quot;DC&quot;. I may add DC later just as an alternative.\r\n=cut\r\n\r\nsub _options_state {\r\n\r\n    return (\r\n        'AL' =&gt; 'Alabama',\r\n        'AK' =&gt; 'Alaska',\r\n        'AZ' =&gt; 'Arizona',\r\n         ...\r\n        'WY' =&gt; 'Wyoming',\r\n    );\r\n\r\n}\r\n\r\nno HTML::FormHandler::Moose::Role;\r\n1;\r\n<\/pre>\n<p>\nWhen I initially created this Role, I had intended to manually validate the Zip Code field using Regexp::Common. I then found that FormHandler has a <a href=\"https:\/\/metacpan.org\/module\/GSHANK\/HTML-FormHandler-0.40025\/lib\/HTML\/FormHandler\/Types.pm\" title=\"FormHandler Types\"  target=\"_blank\">types Module <\/a>with some useful stuff in there, including a zip code. I will try this out instead. It also has types to trim off extra white space. How convenient.\n<\/p>\n<p><span class=\"code-description\">Mover::Form::Travel::Matrix<\/span><\/p>\n<p>\nThis is the actual HTML::FormHandler form, which has <tad-larger>repeatable<\/tad-larger> Address elements. I also opted to include some of the convenient FormHandler Widgets that were created to make use of the Twitter Bootstrap CSS framework. There&#8217;s lots of stuff available with HTML::FormHandler.<br \/>\nThis module is available here on GitHub  <tad-larger> <a class=\"vital-link\"  href=\"https:\/\/github.com\/aibistin\/Mover-Form-Travel-Matrix\" title=\"Mover::Form::Travel::Matrix\"  target=\"_blank\">Mover::Form::Travel::Matrix<\/a><br \/>\n<\/tad-larger>\n<\/p>\n<pre class=\"brush: css; auto-links: false; collapse: false; first-line: 1; gutter: true; light: false; pad-line-numbers: false; smart-tabs: false; tab-size: 4; title: Excerpt from Mover::Form::Travel::Matrix;; toolbar: true; notranslate\" title=\"Excerpt from Mover::Form::Travel::Matrix;\">\r\n\r\nhas '+field_name_space' =&gt; ( default =&gt; 'Mover::Form::Field' );\r\n \r\nhas '+name'        =&gt; ( default =&gt; $form_name );\r\n \r\nhas '+html_prefix' =&gt; ( default =&gt; 1 );\r\n \r\nhas '+is_html5'    =&gt; ( default =&gt; 1 );\r\n \r\nhas '+http_method' =&gt; ( default =&gt; $http_method );\r\n \r\nhas '+action'      =&gt; ( default =&gt; $form_action );\r\n\r\n#----- Mover::Form::Field::Address that is Repeatable\r\n \r\nhas_field 'addresses' =&gt; (\r\n    type         =&gt; 'Repeatable',\r\n    setup_for_js =&gt; 1,\r\n    do_wrapper   =&gt; 1,\r\n    tags         =&gt; { controls_div =&gt; 1 },\r\n    auto_id      =&gt; 1,\r\n);\r\n\r\nhas_field 'addresses.contains' =&gt; ( type =&gt; 'Address', );\r\n \r\nhas_field 'submit' =&gt; (\r\n    type         =&gt; 'Submit',\r\n    widget       =&gt; 'ButtonTag',\r\n    element_attr =&gt; { class =&gt; &#x5B; 'btn', $button_class, $button_size ] },\r\n    do_wrapper   =&gt; 0,\r\n    value        =&gt; 'Get Travel Time'\r\n);\r\n \r\nhas '+info_message'    =&gt; ( default =&gt; 'Starting point.' );\r\n \r\nhas '+success_message' =&gt; ( default =&gt; 'Form successfully submitted' );\r\n\r\nhas '+error_message'   =&gt; ( default =&gt; 'Please fix the errors on this form!' );\r\n<\/pre>\n<p>\nNow, we have a form with a repeatable address field and some fancy Bootstrap CSS, Yippee!<br \/>\nNext up is to create some templates to render the form pages. So, I will use the now familiar <a ref=\"https:\/\/metacpan.org\/module\/Template\" title=\"Template Toolkit\"  target=\"_blank\">Template Toolkit<\/a> to do this.\n<\/p>\n<p class=\"code-heading\">The Address Form Template<\/p>\n<p><span class=\"code-description\">travel_time.tt<\/span><\/p>\n<pre class=\"brush: css; auto-links: false; collapse: false; first-line: 1; gutter: true; light: false; pad-line-numbers: false; smart-tabs: false; tab-size: 4; title: travel_time.tt; toolbar: true; notranslate\" title=\"travel_time.tt\">\r\n&lt;!-- Travel Matrix Form --&gt;\r\n&lt;form name=&quot;&#x5B;% tm_form.name %]&quot; id=&quot;&#x5B;% tm_form.name %]&quot;\r\n  action=&quot;&#x5B;% tm_form.action %]&quot; method=&quot;&#x5B;% tm_form.http_method %]&quot;\r\n  class=&quot;form-vertical&quot; &gt;\r\n\r\n\r\n&lt;fieldset &gt;\r\n   &lt;legend&gt;\r\n      &lt;p class=&quot;lead&quot;&gt;\r\n         &#x5B;%- \r\n             travel_time_heading \r\n             || 'Calculate Moving Truck Travel Time'\r\n         -%]\r\n      &lt;\/p&gt;\r\n   &lt;\/legend&gt;\r\n\r\n&lt;!--  Start messages --&gt;\r\n    &lt;div id=&quot;messages&quot;&gt;\r\n    &lt;p class=&quot;text-success&quot;&gt;&#x5B;%- success_message -%]&lt;\/p&gt;\r\n    &lt;p class=&quot;text-error&quot;&gt;&#x5B;%- error_message -%]&lt;\/p&gt;\r\n    &lt;p class=&quot;text-warning&quot;&gt;&#x5B;%- warning_message -%]&lt;\/p&gt;\r\n    &lt;p class=&quot;text-info&quot;&gt;&#x5B;%- info_message  -%]&lt;\/p&gt;\r\n    &lt;\/div&gt;\r\n&lt;!-- End  messages --&gt;\r\n\r\n    &#x5B;% started_new_row  = 0  %]  &#x5B;%# To specify how many Addresses per line %]\r\n    &lt;!--- four to a line --&gt;\r\n    &#x5B;% FOREACH address_element IN tm_form.field('addresses').fields -%]\r\n        &#x5B;%  IF ((loop.count == 1) || ((loop.count % 5) == 0))   %]\r\n\r\n          &#x5B;% IF ( started_new_row == 1) %]\r\n              &lt;!-- Close previous row before opening a new one. --&gt;\r\n               &lt;\/div&gt; &lt;!-- \/row-fluid --&gt;\r\n          &#x5B;%  END %]\r\n          &lt;div class=&quot;row-fluid&quot;&gt;\r\n          &#x5B;% started_new_row  = 1 %]\r\n        &#x5B;% END %]\r\n\r\n        &lt;div class=&quot;span3 well&quot;&gt;\r\n        \r\n          &#x5B;% IF loop.first %]\r\n              &lt;span class=&quot;text-info&quot;&gt;\r\n                &lt;abbr title='Calculations are based from a starting point in central New York City.'&gt;\r\n                First Address\r\n                &lt;\/abbr&gt;\r\n              &lt;\/span&gt;\r\n          &#x5B;% ELSIF loop.last  %] \r\n              &lt;span class=&quot;text-info&quot;&gt;\r\n                  &lt;abbr title='The next version will have an option for more destination points.'&gt;\r\n                  Last Address&lt;\/abbr&gt;\r\n              &lt;\/span&gt;\r\n\r\n          &#x5B;% ELSE %]\r\n              &lt;span class='text-info'&gt;Address &#x5B;% loop.count %]&lt;\/span&gt;\r\n          &#x5B;% END %]\r\n          \r\n          &#x5B;% address_element.render %]\r\n\r\n        &lt;\/div&gt; &lt;!-- \/span3 --&gt;\r\n    &#x5B;% END %]\r\n\r\n    &#x5B;% IF ( started_new_row == 1) %] &#x5B;%# Close div tag at end of each row %]\r\n        &lt;\/div&gt; &lt;!-- \/row-fluid --&gt;\r\n        &#x5B;% started_new_row  = 0 %]\r\n    &#x5B;%  END %]\r\n\r\n\r\n\r\n&lt;div class=&quot;row-fluid&quot;&gt;\r\n    &#x5B;% tm_form.field('submit').render %]\r\n&lt;\/div&gt; &lt;!-- \/row-fluid --&gt;\r\n&lt;\/fieldset&gt;\r\n&lt;\/form&gt;\r\n\r\n&lt;\/div&gt; &lt;!-- \/row-fluid --&gt;\r\n\r\n&#x5B;% IF ( tm_form.is_valid) %]\r\n\r\n    &#x5B;% IF (my_errors) %]\r\n        &lt;div class=&quot;alert alert-error&quot;&gt;\r\n        &lt;span&gt;&lt;b&gt;&#x5B;% error_message  || 'What a mess!' %]&lt;\/b&gt;&lt;\/span&gt;\r\n        &#x5B;%# One way to loop through a hash %]\r\n        &#x5B;% FOREACH error IN my_errors.values %]\r\n         &lt;span&gt; &#x5B;% error %]&lt;\/span&gt;\r\n         &#x5B;% END %]\r\n        &lt;\/div&gt;\r\n    &#x5B;%  END %]\r\n    \r\n&#x5B;% ELSIF ( tm_form.errors) %]\r\n    &lt;div class=&quot;alert alert-error row-fluid&quot;&gt;\r\n        &#x5B;% FOREACH error IN tm_form.errors -%]\r\n        &lt;span class=&quot;span2&quot;&gt;&#x5B;% error %]&lt;\/span&gt;\r\n        &#x5B;% END %]\r\n    &lt;\/div&gt;\r\n&#x5B;%  END %]\r\n<\/pre>\n<p>\nThe source code for this template is available <a class=\"vital-link\"  href=\"https:\/\/github.com\/aibistin\/TravelTime\/blob\/master\/views\/travel_time.tt\" title=\"travel_time.tt\" target=\"_blank\">here<\/a>.<br \/>\nThere are many other ways to render a <a href=\"https:\/\/metacpan.org\/module\/HTML::FormHandler\" title=\"FormHandler\"  target=\"_blank\">HTML::Formhandler<\/a> form, which you can explore in the <a href=\"https:\/\/metacpan.org\/module\/GSHANK\/HTML-FormHandler-0.40027\/lib\/HTML\/FormHandler\/Manual.pod\" title=\"HTML::FromHandler Docs\" target=\"_blank\">CPAN documentation<\/a>.\n<\/p>\n<p class=\"important\">\nThere is much to explore in HTML::FormHandler and I am sure I will be using it again in future projects.\n<\/p>\n<p>\n<a href=\"https:\/\/twitter.com\/aibistin\" class=\"twitter-follow-button\" data-show-count=\"false\" >Follow @aibistin<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a summary of how I created a repeatable Address Form Module, Mover::Form::Travel::Matrix, using HTML::FormHandler. As part of my TravelTime Application project I needed to create a form to enter multiple location addresses. I could construct the form manually using Template Toolkit, but I would still need to write my own validation and JavaScript [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[21,23,12,20,22],"class_list":["post-427","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-dancer2","tag-htmlformhandler","tag-moose","tag-perl","tag-templatetoolkit"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.aibistin.com\/index.php?rest_route=\/wp\/v2\/posts\/427","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.aibistin.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.aibistin.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.aibistin.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.aibistin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=427"}],"version-history":[{"count":9,"href":"https:\/\/www.aibistin.com\/index.php?rest_route=\/wp\/v2\/posts\/427\/revisions"}],"predecessor-version":[{"id":561,"href":"https:\/\/www.aibistin.com\/index.php?rest_route=\/wp\/v2\/posts\/427\/revisions\/561"}],"wp:attachment":[{"href":"https:\/\/www.aibistin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=427"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.aibistin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=427"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.aibistin.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=427"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}