Cliqon provides a Forms Class as part of the Administration system. We will explain how it works below and detail the API with the following proviso. Cliqon Forms is hard coded to implement a Bootstrap 4 formset. Thus you can definitely put it to good use to expand the Cliqon Administration system into other directions such as eCommerce, a Business Directory or a CRM system. However it will only be useful for a front-end website if that website is written to use a Bootstrap 4 CSS framework. The API works in such a way that you could add support for Material Design, on top of Bootstrap but not use a Material Design framework instead of Bootstrap 4.


So having taken note of these constraints, let us explain how to configure a Formset.

Form types

Cliqon supports three types of form container:


    • a page form or a form that is displayed covering the entire content portion of an administrative page
    • a column form that displays in a column that takes up one half vertically, of an administrative page. A column form invariably accompanies a datagrid, datatree and datalist.
    • a popup form that appears in a modal dialogue in the centre of the screen. The popup form invariable accompanies administrative facilities such as datacard, gallery, calendar and datatable.


As far as Cliqon Administration is concerned, which form display type to use is configured in the Model -> [common]


Our screen shot shows a column formset attached to a datagrid displaying the Model -> string,.

The form process

Within Cliqon Administration, the process of displaying a form to enter or edit data is commanded from one of two places. If the form will be used to enter a new record, an "Add" button will appear in the breadcrumb header of the page. The only exception to that rule is when an "Add" icon is added to a datarow on a tree in order to add a child record. If the form is to be used to edit an existing record where the Record ID will be non zero, the "Edit" icon or button will appear on the row of data.


All data is displayed by Cliqon as some form of Javascript facility or routine. Cliqon does use Third Party libraries such as jqTree, Datatables and Gijgo Grid, as well as tables, cards and lists of its own construction. These latter facilities use Vue to create repeatable components.


Thus all icon and button click events are handled by the Cliq Javascript file. Different Javascript libraries and routines handle events in different ways but they are all normalised into one Event handler in Cliq.Js called crudButton(). This is an AJAX routine that sends sufficient parameters to the getform() routine to get the appropriate response - page, column or popup form..


Once a form is displayed, every form has at least a Submit, Preview and Reset button. If one clicks on Preview, what would generally be sent to the form post processor is displayed. If one clicks on the Submit button, a generic routine is invoked to collect all the data from the form, convert that into a FormData object (so that we can send files uploads with a form as well as stand alone immediate file uploads). Special facilities such as the Code, JSON and Rich Text editors are parsed for their content.


The FormData is sent by AJAX to a generic Form Processor which utilises the Model in order to process the data before updating the database. If the write is successful, a success message is returned, which is displayed on the screen, popup windows are closed, page forms return to their calling page and where appropriate, data displays are updated.


As part of the Form process, HTML5 validation can be configured which will stop the form being submitted if a form is not valid. How and where you want to display error messages is under your control, also you can set tooltips and hints. A form validator library is made available. See http://formvalidator.net/ for more details

The form API

In the Cliqon Class Form{}, we divide the methods into five sections for reasons of convenience. In practice there are four groups of methods. One group and two methods publish the form and set either default data or data from an existing record. One group handles all the common form components such as input, select and textarea. Two groups handle the miscellaneous form components and utilities. Finally one group handles all the complex form components, which as a general rule, contain multiple fields and that you would not expect to find listed in a HTML 5 list of tags. These includes, addresses, tabbed multiple language input, code and json editors etc..


In order to create a form, the publish method reads in a form array from a collection or model. The publish method processes each form component in the correct order (as configured) and the form component is invoked. When a form component is invoked it generates a for row and adds any necessary Javascript to the overall form Javascript.


In most cases, the form is created as a string of HTML which is returned to the crudButton AJAX routine to display in the configured manner.


Let us look at one recognisable component:


       static function frm_text($fld)

       {

                 array_key_exists('class', $fld) ? $fld['class'] = 'form-control '.$fld['class'] : $fld['class'] = 'form-control' ;

                 $frmfld = H::div(['class' => 'form-group row'], self::setLabel($fld),

                         H::div(['class' => self::$cw],

                                 H::div(['class' => 'form-inline'],

                                         self::addIcon($fld, true),

                                         H::input(self::setFldProps($fld)),

                                         self::addIcon($fld)

                                 ),

                                 self::addHelp($fld)

                         )

                 ); self::setForm($frmfld);    

                 $js = "";  self::setFormScript($js);  

               return true;      

       }

In the Form array, this field will have a primary form type of "text" but may have a modern HTML5 subtype such as "number", "email" or "date". The form publish method as it iterates through the form array will select "frm_text" as the sub method and populate the overall form HTML with the a string generated by this component.


You will observe that Form components are written with the HTML Class and tag methods. Also you will observe that the component contains calls to several sub components. These include a sub component to set a label with a star for this field is required. In most cases the width of the label and the width of the componet will be one quarter and three quarters of the width of the row respectively. Icons are permitted both before and after the field but space for them to exist be allowed for in the model. Help text below the input field is permitted (which is a Bootstrap specific way of doing things). Finally appropriate Javascript can be hard coded into a component.


Please note the setFldProps() submethod; a quick look at the submethod will show how a large number of well known form attributes that have to be handled in a special way are configured, but as a general rule, key/value pairs in the form array are passed through without intervention, giving the developer enormous flexibility.


All forms in the Cliqon administration system expect Vue.Js to be used to process the form. When you are configuring forms for your own use, you may use Vue, use your own library or not use any library at all. In our detailed API reference, we will assume the use of Vue.


When you look at a model record in the database or a development model file, you will find TOML array snippets. The following example is from the dbuser model.


[form]

       type = 'columnform'

       [form:formheader]

               action = '/api/{common.lcd}/update/dbuser/'

               method = 'POST'

               enctype = 'multipart/form-data'

               name = 'dataform'

               id = 'dataform'

               class = 'form-horizontal'


       [form:formfields]

; Hidden

       [form:formfields:id]

               v-model = 'id'

               type = 'hidden'

               defval = '0'

               display = 'iu'


       [form:formfields:c_lastmodified]

               v-model = 'c_lastmodified'

               type = 'hidden'

               defval = ''

               display = 'cu'


       [form:formfields:c_whomodified]

               v-model = 'c_whomodified'

               type = 'hidden'

               defval = 'admin'

               display = 'cu'        


; Visible


       [form:formfields:instructions]

               type = 'rowtext'

               text = '9999:Complete all fields and press enter'

               order = 'a1'

               class = 'text-muted'


       [form:formfields:c_username]

               v-model = 'c_username'

               id = 'c_username'

               type = 'text'

               placeholder = '{fields.c_username.title}'

               label = '{fields.c_username.title}'

               class = 'isunique'

               style = 'width: 60%;'

               helptext = '9999:Between 5 and 12 characters all lowercase letters'

               required = 'required'

               minlength = '5'

               maxlength = '12'

               order = 'aa'

               display = 'c'

               autofocus = 'true'

               data-table = 'dbuser'

               data-tabletype = ''


       ............

               ............


; Buttons

       ..............


; Form ends


The array key [form] specifies this part of the model as the part that responds to Service = form in stdModel(). Array keys [formheader] and [formfields] will be used by the form Publish method internally. The Publish method will expect a number of formfields as subarray keys, supported by their child arrays.


You should understand that in [formheader], the array of key/value pairs are converted to attributes of a form.


The key name in [formfields] is just an unique name and has no useful significance. All emphasis is placed on the contents of the child array associated with that key name. For convenience we divide our form into invisible or hidden elements and visible. This is an arbitrary division. In the API reference below, we have divided the elements of the child arrays into Required and Optional. Your Form will not work or throw some for of error if Required elements for a given component are not present.


[rowtext]

       ;required

type = 'rowtext'  ;Puts any configured text in a row

text = '9999:Complete all fields and press enter'  ;Note how we are entering the arguments for a cStr()

order = 'a1'  ;Places this form field as number one in the order


;optional

class = 'text-muted'  ;Whatever you want


[hidden]

       ;required

       type = 'hidden'  ;Hidden element

       v-model = 'id'  ;Vue field name

       defval = '0'  ;Default value if insert is zero, meaning an insert

       display = 'iu' ;Must exist to initialise record and must exist for an update


[text]

       ;required

type = 'text'  ;Input type = text

v-model = 'c_common'  ;Name of field

label = '9999:Common'  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'c'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu


;optional

id = 'c_common'  ;Sometimes needed when the Component must have an ID

       subtype = 'email'  ;Any HTML5 input type such as email, number, date, datetime etc.

       placeholder = '9999:Common'  ;Note how we are entering the arguments for a cStr()

       helptext = '9999:Between 5 and 12 characters all lowercase letters'        

       or helptext = 'Help!|x'  ;How to treat entry as literal

       class = 'isunique' ;Note how we use classes to invoke Javascript routines. List of available routines below

       style = 'width: 60%;'  ;It appears difficult to add classes for display purposes to form controls such as        width, therefore use style to manage such requirements

       required = 'required'  ; An entry in this field is required

       minlength = '5'  ;Minimum length of entry

       maxlength = '12'  ;Maximum length of entry

       step = '10'  ;Numeric entries, configures options for virtual select

       autofocus = 'true'  ;If first field automatically put cursor in this field

       data-table = 'dbuser'  ;For nextref, nextindex and isunique etc, table to look up

       data-tabletype = ''  ;For nextref, nextindex and isunique etc, table type to look up

       sficon = 'puzzle-piece'  ;Font Awesome icon to display as suffix (after field) to invoke some sort of form activity

action = ''  ; Required if using sficon. See section below

pricon = ''  ; See above. Icon to display as prefix (before field)

praction = ''  ; Required if using pricon. See section below

pattern = ''  ; See example.cfg

defval = 'string'  ;Default value for the field

readonly = 'true'  ;Set field to readonly

disabled = 'true'  ;Set field to disabled

taborder = '1'  ;Field tab order


[textarea]

       ;required

type = 'textarea'  ;Field type = textarea

v-model = 'c_notes'  ;Name of field

label = '7:Notes  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'c'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu


;optional - see [text]


[select]

       ;required

type = 'select'

v-model = 'c_category'  ;Name of field

label = '196:Category'  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'c'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu

       listtype = 'dynamic'  ;From where will the Form select method obtain the options? dynamic - look up the dropdown list entries using Q::cList(listname), static = options will contain string of keys and values as "admin|Administrator,operator|Operator - note how pairs are separated by a comma and keys are separated from values by a vertical bar, staticidm = as static but value element is formatted by Q::cStr(() - cr|9999:(I)ncome,dr|9999:(E)xpense

       options = 'usergroups'  ;If listtype = dynamic

options = 'admin|Administrator,operator|Operator,visitor|Visitor'  ;If listtype = static

options = 'cr|9999:(I)ncome,dr|9999:(E)xpense'  ;If listtype = staticidm

;optional - see [text]


[radio]

       ;required

type = 'radio'  

; Then see [select]

;optional - see [text]


[checkbox]

       ;required

type = 'checkbox'  

; Then see [select]

;optional - see [text]


[slider]

       ;required

       type = 'slider'        

       subtype = 'text'

       v-model = 'd_reputation'

       id = d_reputation

       class = 'slider'

       data-slider-min = '0'

       data-slider-max = '5'

       data-slider-step ='1'

       data-slider-value = '3'

       defval = '3'

label = '9999:Reputation'  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'c'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu


;optional - also see [text]

helptext = '9999: Values between 0 and 5 where 5 is the highest'


[json]

       ;required

type = 'json'  ;Field type = textarea

v-model = 'c_notes'  ;Name of field

label = '7:Notes  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'cu'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu


;optional - see [text]


[file] - Implements Dropzone

       ;required

id = 'd_url'

v-model = 'd_url'

type = 'image'

subtype = 'file'

label = '185:File'

class = 'h80 dropzone'

sficon = 'trash'

action = 'deleteimage'

order = 'am'

defval = 'blank.gif'

data-uploadurl = '/api/en/fileupload/dbitem/'

data-subdir = 'tmp/'

data-filescollection = 'file'

display = 'cu'


;optional - see [text]


[image] - Implements Dropzone

       ;required

id = 'd_image'

type = 'image'

subtype = 'file'

label = '217:Image'

class = 'h80 dropzone'

sficon = 'trash'

action = 'deleteimage'

order = 'ar'

defval = 'blank.gif'

data-uploadurl = '/api/en/fileupload/dbitem/'

data-subdir = '{gallery.subdir}'

data-filescollection = 'file'

display = 'cu'


;optional - see [text]


[boolean]

       ;required

type = ''  ;Field type = textarea

v-model = 'c_notes'  ;Name of field

label = '7:Notes  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'c'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu


;optional - see [text]


[tag]

       ;required

type = ''  ;Field type = textarea

v-model = 'c_notes'  ;Name of field

label = '7:Notes  ;Note how we are entering the arguments for a cStr()

       order = 'aa'  ;Set order in form components display (from a1 to zz)

       display = 'c'  ;(c)reate, (i)nitialize or (u)pdate - entries such as c, cu, iu


;optional - see [text]


[boolean]

       ;required

type = 'boolean'

subtype = 'checkbox' ;Bootstrap 4 extra that displays field as on / off slider

v-model = 'd_iscompany'

defval = 'false'

order = 'ae'

display = 'cu'

helptext = '9999:Is this a Company record - check for true'

label = '9999:Is Company?'


;optional - see [text]


Above, we have detailed the common form components. Below we provide a list of the special Cliqon components and form components that provide specialised facilities.


    • idiomtext - type = 'idiomtext' and subtype = 'text' or 'textarea', other options as text or textarea component; The component display a text field or a textarea with a set of tabs above with the set of configured languages. Also there is a globe icon which when clicked, invokes an automatic translation facility to copy text entered in the default language field, into the other fields and then translate it. To use the facility, a valid Bing key must be entered in the main configuration file. If the subtype is set as 'textarea' and a class of 'texteditor' is added, then each textarea will be replaced with a Trumbowyg text editor.
    • level - type = 'level'; displays a particular type of component with three numeric text fields inline in a row to configure or update c_level. The entries in the individual fields are watched and the combined value in the form 99:99:99 is shown in the final readonly field.
    • password - type = 'password'; displays two fields, inline, in a row to enter and confirm a password. You may configure the name of the field.
    • date - type = 'date'; Displays a datepicker for the field. You may configure the name of the field.
    • daterange - type = 'daterange'; Displays two fields in line and two datepickers. Fields are configured as hard coded as d_datefrom and d_dateto.
    • autocomplete - type = 'autocomplete'; Use the same configuration as a 'select' field to choose the possible options for the field.
    • fullname - type = 'fullname'; Configures a series of fields, to enter the values for: d_firstname, d_midname, d_lastname, d_title.
    • address - type = 'address'; Configures a series of fields to enter the value for: d_addr1, d_addr2, d_suburb, d_postcode, d_city, d_region, d_country. Default values can be set see Appendix 'Form Examples'.
    • maplocn - type = 'maplocn'; Displays two fields inline plus two clickable icons. The first icon invokes an instance of Google maps in a popup window and attempts to identify the map coordinates for an address created by an address field, as explained above. The second icon displays a Google map in a popup window. The operator moves the map about until the address is located manually and visually. In both Google map cases the Latitude and Longitude coordinates are transferred to the two form fields. These two input fields are configured as d_mapx and d_mapy respectively.
    • creditcard - type = 'creditcard'; The form component has been defined to display a complete Credit Card entry but remains unconfigured as to which fields will be used and the Javascript to animate and validate the entries in this field.
    • identity - type = 'identity'; This form configures two inline fields specific to Spain to enter the number of the identity document and the type of identity.
    • model - type = 'model', subtype = 'table' or 'tabletype'; Displays two select dropdowns with options drawn from the datadictionary for "tables' and 'tabletypes'. Values are recorded in d_table and d_tabletype. Used internally.


For more details see the Appendix with more form examples.

Available Javascript routines

The following Javascript routines are configured in Cliq.Js Form component.

As Classes

Cliqon currently responds to the following additional classes in a form component:


    • isunique - Checks to see if a value entered in the field already exists in the table for the configured tabletype. The routine is told which table and tabletype to use in 'data-table' = '' and 'data-tabletype' = '' in the form component configuration.
    • nextref - Gets the next reference specifically for a c_reference field where type of reference is in the form chrs+open bracket+number+close bracket. Eg. str(99) or doc(1). The routine is told which table and tabletype to use in 'data-table' = '' and 'data-tabletype' = '' in the form component configuration. The default value must be supplied. Last entries are recorded in the table dbindex, so that if there is a need to adjust the starting reference for some reason, the value of the entry can be set manually.
    • datepicker - Displays a datepicker.
    • nextid - Gets the next numeric id specifically for any field. The routine is told which table and tabletype to use in 'data-table' = '' and 'data-tabletype' = '' in the form component configuration. The default value must be supplied. Last entries are recorded in the table dbindex, so that if there is a need to adjust the starting number for some reason, the value of the entry can be set manually. The idea behind this facility is to set a number for things like Order IDs.
    • nextentry - As nextid but the idea of a next number is replaced with a next alphanumeric reference. Great for Stock Codes.
    • slugified - On keyup or blur, converts any entry in the field into a slug form - Eg. replacing spaces with hyphens and flattening any accents.
    • tinymce - Displays a TinyMCE editor for the field. Give careful consideration to the design of your form and how it should be displayed in order to use this facility and the following two.
    • codeeditor - Displays an instance of Codemirror
    • jsoneditor - Displays an instance of JSON Editor


Any additions or alterations will have to be added to the formMounted function in the Cliqf() Class within Cliq.Js.

As field icons

Cliqon forms currently respond to clicks on the following icon actions:


    • lookupcompany - invokes a popup to lookup a Company name derived from c_name in dbcompany.
    • deleteimage - Attached to a file or image field. Used to delete the file from the entry field and consequent FormData, so that a new file or image can be chosen.


Any additions or alterations will have to be added to the formMounted function in the Cliqf() Class within Cliq.Js.

Buttons array

All forms can have multiple buttons configured that appear at the bottom of the form.


; Buttons

       [form:buttons]

               [form:buttons:submit]

                       type = 'button'

                       class = 'btn-danger'

                       title = '105:Submit'

                       action = 'submitbutton'

                       icon = 'email'


               [form:buttons:preview]

                       type = 'button'

                       class = 'btn-success'

                       title = '121:Preview'

                       action = 'previewbutton'


               [form:buttons:reset]

                       type = 'button'

                       class = 'btn-warning'

                       title = '122:Reset'

                       action = 'resetbutton'


               [form:buttons:cancel]

                       type = 'button'

                       class = 'btn-danger'

                       title = '136:Cancel'

                       action = 'cancelbutton'


In the example shown above, all buttons are configured as type = 'button'. We have tried using 'submit' and 'reset' but it really causes problems with Vue. All buttons are Bootstrap4 buttons, thus btn-small is assumed and you can set the colour. The string in the title is converted by Q::cStr(title). The action must be configured in Cliqf.vueform.methods{}. Finally, if you do want to include an Font Awesome icon after the title, add the entry icon = 'Font Awesome icon name'.

Free text

As each form component is processed, the output from the component is passed to the Static Class variable called $formhtml. When the form is published the content of $formhtml is read and sent back to the AJAX routine to be displayed. We have already stated that each form component is processed in order and that order is configured for each component in the form configuration array.


Bearing these facts in mind, we have created two simple form components to add configurable free text to a form. We offer type = 'rowtext' and type = 'rowstring':


    • Rowtext - This is used for blocks of text and instructions which is displayed in column with the form fields. That is, a blank label is assumed and the whole component is treated as a form-group and row. See the example above. It can be used for instructions and additional help text.
    • Rowstring - Only needs two entries for the component array - an order and a string of Html. An example might look like:


[form:formfields:openfieldset]

               order = 'ba'

               html = '<fieldset class=""><legend>Configuration</legend>'


...........


[form:formfields:closefieldset]

               order = 'bz'

               html = '</fieldset>'


The one drawback with this approach is that it does not support multiple languages. However for that we offer type = 'fieldset'. But you still need to close the fieldset manually, as shown above.

Notes

Make sure that [common] is correctly configured as well. Make sure that your display service (datagrid etc.) is configured to invoke the form.

You may omit the 'fa-' characters before all Font Awesome icons in a form configuration.

To be implemented in future version - type=list, output, type=search


Created with the Personal Edition of HelpNDoc: Easily create CHM Help documents