Nested Forms

// Website backends begin with a consideration of the real life entities the site will need to store and process. Each real life entity will amount to a data class and have properties // that each amount to a data class member. Members may be optional or compulsory (mimimum population 0/1), and may be singular or multiple (maximum population 1/0). In some cases the // properties are composite, making the 'values' instances of another (sub) class. In a repository of job candidates for example, spoken languages can be a simple list but it is usual // to state for each, the level of proficiency. So "Languages Spoken" is a data class and a sub-class of candidate. Once you have the set of data classes, you have the outline of the // forms the site will use. The main point of adopting the HDB, a hierarchical database regime, is so that real life entities fit directly into ready made repositories. It is also the intention that forms fit real life entities. This is known as the form-class guideline.

Although form layout matters, of greater importance is how it will operate, what buttons will it have and what happens when they are pressed. There are two tags for declaring form buttons within a form definition, <xformBut> and <xlinkBut>. Both give rise to instances of the hdsVE derivative hdsButton, so both produce buttons in the HTML. The <xformBut> tags are form action buttons that will always submit data in a HTTP POST request and thus invoke a form handler which will in all cases produce a HTTP response. The <xlinkBut> buttons can do anything JavaScript permitting, except invoke form handlers.

Dissemino assumes browsers are able to process JavaScript and automatically generates JavaScript functions for form validation. The validation is only partial, restricted mostly to checking field entries are of the correct format, but it prevents obvious errors from wasting server throughput. There will be an entry function for each form action button, mostly consisting of calls to standard scripts for the fields based on data type. The entry fuction will be called by the onsubmit event.

JavaScript is also called by the <xlinkBut> buttons. An abort button or any other that would navigate away from the page and thus the form, may check for edits and display an alert bot to ask the user to confirm. JavaScript is also used to handle composite members. A common approach is for the form to present a table of the subclass objects with a blank line at the bottom. These are fields that can be filled in to add an entry.

In HTML <form> tags cannot be nested, but the forms themselves can be nested by other means. Assuming the form-class guideline, forms for sub-class objects can be incorporated into the main class object form by simple dint of the <xformRef> tag. Only the top level <xformDef> or <xformRef> acting for the main data class, can produce the <form> tag. In the call to hdsFormref::Generate for a nested <xformRef>, the <form> tag is supressed. Note however, that only <xformRef> can be nested. <xformDef> cannot be.

Naming Conventions

Dissemino ensures form names are unique among forms and form handler names are unique among form handlers, but it does not limit the names in any other way. Voluntary adoption of a naming convention one is strongly advised. The HadronZoo form naming convention uses the prefix of 'form_' for form names and 'fhdl_' for form handler names. For multi-stage forms, the names are postfixed with '_stage1', '_stage2' and so on. The rest of the name is expected to reflect the native data class of the form. It is also advised that data class names are themselves descriptive. The form and form handler names are not visible to the end user, only the URLs used by form buttons ever appear in the browser address bar. The naming convention is purely for clarity in the configs.

The form action URLs must be unique among all POST URLs and ideally, unique among all URLs. Each form reference introduces a combination of form handler and class context for every form action button in the form definition. This, given the URLs are what the user will see in the browser address bar, can make the URLs harder to apply a naming convention to.

Config Read Order

In the configs the <xformDef> tag is processed by hdsApp::_readFormDef which has two variants - One for independent <xformDef> tags (outside any page/article definition), the other for in-situ <xformDef> tags. In the independent case, hdsApp::_readFormDef creates a hdsFormdef instance, places a pointer to it in the hdsApp map m_FormDefs and returns a hzEcode. In the in-situ case, hdsApp::_readFormDef also creates a hdsFormdef instance and places a pointer to it in m_FormDefs. However instead of returning a hzEcode, it goes on to create a hdsFormref instance and returns a pointer to it for inclusion in the page/article array of visual entities.

In the configs, both in-situ and independent <xformDef> tags preceed the definitions of the form handlers they refer to. Form handler names are introduced by the 'action' attribute in either the <xformDef> and >xformBut> tags, allowing actions to be specified for buttons individually or for the form as a whole and then inherited by buttons. Form handler names can be duplicated within a <xformDef> but only because form buttons can sometimes be repeated for decorative reasons. Other than this, form handler names are checked for uniqueness against the map hdsApp::m_FormHdls. The program will terminate if a name is already in use. Assuming the name is available it is added to the hdsApp::m_FormHdls map but with a NULL hdsFormhdl pointer. Each named form handler must ultimately be defined, so at the end of the config read process, hdsApp::m_FormHdls is checked for any remaining NULL pointers. The program will terminate if any are found.

Once a form is defined, however it is subsequently referenced it will always appear the same, have the same buttons which will POST the form data through to the same form handlers. However the form handlers will not necessarily be operating under the same class context. Given the context can vary it is clear the context cannot be set in the form definition so must be set in the form reference. This brings us to the differences between the two hdsApp::_readFormDef variants and between the idependent and in-situ <xformDef> tags. Using the PostAddr and Person class example, the below illustration is of a form for creating/editing a Person defined within a page and containing two references to an independently defined form for creating/editing a PostAddr.

Firstly the form for PostAddr is defined independently:-

 <xformDef name="form_PostAddr" class="PostAddr" action="fhdl_PostAddr">
  ... Some supportive HTML tags ...
  <xformBut name="Save"/>
 </xformDef>
 <xformDef name="form_PostAddr" class="PostAddr">
  ... Some supportive HTML tags ...
  <xformBut name="Save" action="fhdl_PostAddr"/>
 </xformDef>
 Note the action can either be vested with the <xformDef> tag or its sub-tag <xformBut>.

Then we have independent or in-situ, the Person form:-

 <xformDef name="form_Person" class="Person" action="fhdl_Person" url="/person">
  ... Some supportive HTML tags ...
  <xformRef form="form_PostAddr" context="Person.HomeAddr" url="/personHome"/>.
  <xformRef form="form_PostAddr" context="Person.WorkAddr" url="/personWork"/>>
  ... Some more supportive HTML tags maybe ...
 </xformDef>