On March 26, 2019 we launched new MODX Forums. Please join us at the new MODX Community Forums.
Subscribe: RSS

  • FormIt is my favorite MODx addon of all time - it makes form processing actually pleasant. However, the need for the uncached [tt][[!+prefix.fieldname]][/tt] placeholders and FormItIsSelected/ FormItIsChecked has made it very hard to manage complex HTML forms.

    The problem:

    • Templating: The only good way to template form fields right now is to create a chunk for each field (text field, check box, etc...), but managing that many chunks is very time-consuming. Without using field chunks, you are stuck using repetative HTML that is hard to maintain: if you change the name of a field, for example, you may have to change it in the field itself, the label, value placeholder, error placeholder, label "for" and field "id", email report, help text, and possibly more.
    • Performance: Outputting a simple HTML list of countries with FormItIsSelected for each one, for example, results in significant performance hits. Using chunks as described above can also cause performance hits, because you may resort to using generated placeholders such as [tt][[!+[[+prefix]].error.[[+name]]]][/tt] that need to be processed twice (or more with output filters).
    • [li]Email reports: If you want a custom email report, you must build it by hand every time with labels and placeholders for every field.



    • Use only one template chunk for all form fields (text field, select field, option field, etc...). This simplifies maintenance by allowing you to work with all form fields at once just as you normally would but without forcing you to repeat your changes for every single text field in your form. This will also allow you to maintain multiple form "styles" for all fields by simply switching the field template. Note regarding performance: the "sub-template" (e.g. text field template) is extracted from the field chunk by using a single "explode" and is temporarily cached during the lifetime of a single request using the same system splittingred uses to cache file-based chunks. This seems to keep performance about the same as using separate chunks for each field.
    • Support a field wrapper template, which allows you to standardize HTML for all form fields. This is a good place to put your [tt]<label>[/tt] and surrounding [tt]<div>[/tt] or [tt]<li>[/tt] elements without having to repeat them for each field.
    • Support FormIt value and error placeholders without worrying about prefixes or performance. The field template and wrapper template both have simple placeholders for [tt][[+error]][/tt], [tt][[+error_class]][/tt], and [tt][[+current_value]][/tt]. These values are generated by fetching the FormIt placeholders for the field with the prefix "fi.". If you need to change the prefix, it needs to be overriden only once for each field.
    • Support infinite field types and custom field values. If you want to use a field type called autocomplete with the value connector set to "autocomplete.php", you can!
    • Support groups of checkboxes, radios, selects, and other multiple or nested field groups. These use two field types from the field template: an "outer" field type (such as select, checkbox, or radio) and an "inner" field type (such as option for selects and bool for checkboxes and radios). The inner field type is automatically detected for checkbox, radio, and select, but can be specified if necessary.
    • Allow overriding of outer or inner fields with your own HTML, chunks, or snippets. - Note: Snippets or parameters have not been implemented yet, so currently you’d have to use a chunk or HTML with a snippet call inside of it.
    • Smart caching and performance boosts for nested fields. Since outright caching is impossible due to the changing value of "current value" or "selected" for each user and instance, a "smart caching" system is needed, mostly for fields that use multiple checkboxes, radios, and option fields, which can really affect performance. The inner HTML for these fields is cached by default, and a simple "str_replace" is used to add "selected=selected" or "checked=checked" in the right place. This vastly improves performance over the FormItIsSelected and FormItIsChecked for large sets of options, although you can always disable caching and/or use those instead if needed.
    • Automatically generate label names. This is actually very simple but requires that you use a naming convention for your field names. For example, using lowercase_field_names_with_underscores can be easily made into a readable label by adding [tt][[+label:default=`[[+name:replace=`_== `:ucwords]]`]][/tt] into your template chunks. If you don’t specify a label, one will be generated for you. This may later be standardized into a simple [tt][[+label]][/tt] placeholder.
    • Automatically generate email reports. Most email reports have the same format for each row, such as [tt]<b>Field Name</b>: field value[/tt]. A FormIt hook is used to create a single placeholder with all field labels and values iterated through a row template chunk. Placing this placeholder into a email report template along with the [tt][[*pagename]][/tt] or similar TV placholder allows you to use the same report template for every form.


    The Result:
    Here is an example form. It requires only two template chunks for the fields (one for the outer wrapper, and one for the various field types) and two chunks for the email report (exampleFormItEmailReport and formReportRow). A fully-commented version of this example along with all required chunks is included in the /elements/chunks/ directory.
    [[!FormIt? &hooks=`spam,fiProcessArrays,fiGenerateReport,email,redirect` &emailTpl=`exampleFormItEmailReport` &emailTo=`[[++emailsender]]` &emailSubject=`New message from [[++site_name]] [[*pagetitle]] page.` &redirectTo=`6` &submitVar=`submitForm` &figrTpl=`formReportRow` &validate=`stuffgoeshere`]]
    <div>[[!+fi.validation_error_message]] </div>
    <form id="formExample" action="[[~[[*id]]]]" method="post">
      [[!field? &name=`name`]] <!-- type defaults to text -->
      [[!field? &type=`text` &req=`1` &name=`email` &tpl=`aDifferentTemplate` &outer_tpl=`ADifferentOuterTpl`]]
      [[!field? &type=`hidden` &outer_tpl=`` &name=`blank`]]
      [[!field? &type=`select` &default=`1` &name=`country` &label=`Your Country:` &options_chunk=`optionsCountries`]]  
      [[!field? &type=`textarea` &class=`elastic` &req=`1` &name=`message` &label=`Comment`]]
      [[!field? &type=`radio` &req=`1` &name=`color` &label=`Your Favorite Color:` &default=`` &options=`Red==red||Blue==blue||Other==default`]]
      [[!field? &type=`select` &name=`favorite_things` &multiple=`1` &array=`1` &options=`MODx||Money||Power||Other`]]
      [[!field? &type=`customtype` &name=`custom_field_type` &note=`Make sure you add this custom field to the &tpl chunk!` &custom_placeholder=`custom_value` &another_custom_placeholder=`And another custom value` &options=`One==1||Two==2||Three==3` &option_type=`radio`]]
      [[!field? &type=`submit` &name=`submitForm`]]


    Current status:

    I have had great performance boosts with selects and radios, and managing, maintaining, and templating forms has been a dream.

    This component is exactly one step away from a MODx Revolution form generator. All that is needed is a wrapper snippet that grabs the values of a custom database table or template variable and uses $modx->runSnippet to run the FormIt snippet and iterate through the field snippet calls.

    FormitFastPack is available on GitHub at https://github.com/yoleg/FormitFastPack. Feel free to try it out (upload it to the root of your installation and copy and paste the snippets and chunks from the /elements/ folder) but I have only tested it on one installation (MODx 2.1) and am still improving it. After further testing on a few more sites, after I am sure I won’t be making major changes to the interface, I will release it into the repository. Feedback and suggestions are always appreciated!
      WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area
    • Awesome work Oleg ... I can’t wait to see this roll out as a front end to FormIt.

      For those curious about how templating is handled on the forms themselves, the outer-wrapper chunk tpl file for each form element: field.chunk.tpl
      <div class="[[+outer_class]]" id="[[+name]]_wrap"> 
      <label for="[[+name]]" title="[[+name:replace=`_== `:ucwords]]">[[+label:default=`[[+name:replace=`_== `:ucwords]]`]] [[+req:notempty=` *`]]</label>
      [[+current_value:notempty=`<span class="info"><em>Current value: [[+current_value]]</em></span>`]]
      [[+note:notempty=`<span class="info"><em>[[+note]]</em></span>`]]
      [[!+error:notempty=`<span class="error">[[!+error]]</span>`]] 

      And the individual elements chunk tpl: fieldTypes.chunk.tpl
      <!-- text -->
        <input type="[[+type]]" name="[[+name]]" id="[[+name]]" value="[[+current_value]]" class="[[+class]][[+error_class]]" size="[[+size:default=`40`]]">
      <!-- text -->
      <!-- hidden -->
        <input type="[[+hidden]]" name="[[+name]]" value="[[+current_value]]">
      <!-- hidden -->
      <!-- textarea -->
        <textarea id="[[+name]]" class="[[+type]] [[+class]][[+error_class]]" name="[[+name]]">[[+current_value]]</textarea>
      <!-- textarea -->
      <!-- checkbox -->
      <span class="boolWrap">
      <input name="[[+name]][[+array:notempty=`[]`]]" type="hidden" value="" />
      <!-- checkbox -->
      <!-- radio -->
      <span class="boolWrap">
      <input type="hidden" name="[[+name]]" value="" />
      <!-- radio -->
      <!-- select -->
      <select name="[[+name]][[+array:notempty=`[]`]]" id="[[+name]]" class="[[+class]]"[[+multiple:notempty=` multiple="multiple"`]][[+title:notempty=` title="[[+title]]"`]]>
        [[+header:notempty=`<option value="[[+default]]">[[+header]]</option>`]]
      <!-- select -->
      <!-- static -->
      <span class="static_field">[[!+[[+name]]]]</span>
      <!-- static -->
      <!-- submit -->
      <input id="[[+name]]" class="button" name="[[+name]]" type="[[+type]]" value="[[+message:default=`Submit`]]" />
      <input id="[[+name]]-clear" class="button" type="reset" value="[[+clear_message:default=`Clear Form`]]" />
      <!-- submit -->
      <!-- option --><option value="[[+value]]">[[+label]]</option><!-- option -->
      <!-- bool -->
      <span class="boolDiv [[+class]]">
      <input type="[[+type]]" class="[[+type]]" value="[[+value]]" name="[[+name]][[+array:notempty=`[]`]]" id="[[+key]]"  /> 
      <label for="[[+key]]" class="[[+type]]" id="label[[+key]]">[[+label]]</label></span><!-- bool -->
        Ryan Thrash, MODX Co-Founder
        Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
      • Digital Butter - MODX Premiere Partners Reply #3, 10 years, 3 months ago
        Woah, this looks super awesome!

        +1 for FormIt being my favourite MODX addon too.
        • I have made a transport package and uploaded it to GitHub: https://github.com/downloads/yoleg/FormitFastPack/formitfastpack-0.1.0-beta.transport.zip (or go to github.com/yoleg/FormitFastPack and click on downloads). If anyone wants to test it before I release it, that would be much appreciated.

          Main changes I made since my last post:

          • Changed the names of the template chunks to fieldWrapTpl and fieldTypesTpl to avoid a potential mix-up with existing chunks.
          • Added a build script with a default property set for the field template.

          Changes I hope to add in the future: (What do you guys think of these?)

          • Add a "fieldSetDefaults" snippet that will set the default values for all field snippets below it. The goal is to allow default values limited to a single form. This would be much easier than creating a property set for each form.
          • I am rethinking my decision to limit smart caching to nested fields only. The disadvantage of smart caching is that you cannot use any output filters with the current_value, error, etc..., so I only intended it to be used with options and checkbox/ radio sets. However, I might add optional smart caching for fields that don’t need output filters, which might further reduce load times for very large forms. Smart caching in this case means using str_replace to add in variable values to a cached chunk by searching for value="*" or a static placeholder.
            WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area
          • This thing has much promise I think. I do think there’ll be times when you want to have a couple of options for wrappers, such as a side-by side label for text inputs, and a label on top for textareas.

            Ideally a drag-and-drop form builder UI would be incredible, and I suppose something like a Wufoo would be a great inspiration there: http://wufoo.com/
              Ryan Thrash, MODX Co-Founder
              Follow me on Twitter at @rthrash or catch my occasional unofficial thoughts at thrash.me
            • I do think there’ll be times when you want to have a couple of options for wrappers, such as a side-by side label for text inputs, and a label on top for textareas.

              Isn’t the easiest way to do this just to switch the outer_tpl to a different chunk? What is another way I can implement this?

              Ideally a drag-and-drop form builder UI would be incredible.

              I agree. I haven’t learned enough about MODExt to do this anytime soon - although I’ll code the PHP side of it if anyone wants to contribute the JS.

              I was actually thinking of using the MultiItemsGridTv (http://modx.com/extras/package/migx) to build a simple form manager for clients. It will make it easy to customize the forms for each site’s custom field parameters and produces a nice JSON-format array.

              Some more changes to interface:

              • Removed inner_chunk and options_chunk as parameters
              • Added the following (for both inner_ and options_): options_element (name of a chunk or snippet), options_element_class (e.g. modChunk or modSnippet), and options_element_properties (JSON array of parameters to pass to the element)
                WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area
              • Submitted to the repository - please report bugs smiley.
                  WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area
                • What is the best way to make <optgroup>s using FormitFastPack?
                  I want to output something like:

                    <optgroup label="Swedish Cars">
                      <option value="volvo">Volvo</option>
                      <option value="saab">Saab</option>
                    <optgroup label="German Cars">
                      <option value="mercedes">Mercedes</option>
                      <option value="audi">Audi</option>
                  • Thank you, this is a great idea! Hope the drag and drop comes along soon, formit may be powerful but man can it get tedious.
                      Ben Morrison
                      Hacking templates to pieces since 2003
                    • @Lacks: Probably the best way would be to create a snippet that generates the entire option HTML block (or even a static chunk) and use the parameters &options_element=`SnippetName` &options_element_class=`modSnippet` &options_element_properties=`{"JSON":"array","of":"properties to pass to the element"}`. The field snippet should be able to put in the proper "selected" attribute directly into your HTML for you.

                      @maroonlover: Thanks. Drag and drop will probably not be done by me. I like being able to have full control over the HTML, and that was the goal with FFP (in addition to form-building speed). FFP would be useful for a drag-and-drop app to give the admin more customization over the forms, though.
                        WebsiteZen.com - MODX and E-Commerce web development in the San Francisco Bay Area