Skip to content
Snippets Groups Projects
Select Git revision
  • 4f5704748294294870a71244e9f3e85d7dac9d00
  • develop default
  • documentation
  • B21786-wrapUnexpectedException-fatal-error
  • F10114glyphiconToFontAwesome
  • F21622-settings-table-changes
  • F17481_BS_Modal_window
  • F20975_Dynamic_DateTimePicker
  • revertB5221downloadModal
  • B21533-Hidden-Pill-Required
  • B21510_Validation_error_when_date_field_is_left_empty
  • F8044-Transactions
  • master protected
  • F12532-view-sip-in-Browser-consol-log
  • S21288-Store-Parent-Remove-Prefix
  • F21203-Render-MultiSql-Columns-like-Subrecord
  • F11535_ipa-qfq-db-editor
  • F21130-multiform-toggle
  • S20463-V-Store-not-updated-after-form-save
  • B18601-typeahead-sanatize-applied-to-value
  • F16113-MultiAction
  • v25.6.0
  • v24.12.0
  • v24.10.0
  • v24.7.0
  • v24.5.1
  • v24.5.0
  • v24.3.0
  • test-alfred20
  • v23.10.1
  • v23.10.0
  • v23.6.4
  • v23.6.3
  • v23.6.2
  • v23.6.1
  • v23.6.0
  • v23.3.1
  • v23.3.0
  • v23.2.0
  • v23.1.1
  • v23.1.0
41 results

Form.rst

Blame
  • Form.rst 217.75 KiB

    Form

    General

    Important

    Primary key: QFQ expect that each table, which will be loaded into a form, contains a primary key called id. That one should be autoincrement. It's not necessary to create a FormElement id in a form.

    • Forms will be created by using the Form Editor on the Typo3 frontend (HTML form).

    • The Form editor itself consist of two predefined QFQ forms: form and formElement - these forms are regular updated during installation of newer QFQ versions.

    • Every form consist of a) a Form record and b) multiple FormElement records.

    • A form is assigned to a table. Such a table is called the primary table for this form.

    • Forms can roughly categorized into:

      • Simple form: the form acts on one record, stored in one table.
        • The form will create necessary SQL commands for insert, update and delete (only primary record) automatically.
      • Advanced form: the form acts on multiple records, stored in more than one table.
        • Fields of the primary table acts like a simple form, all other fields have to be specified with action/afterSave records.
      • Multi form: (multi-form) the form acts simultaneously on more than one record. All records use the same FormElements.
        • The FormElements are defined as a regular simple / or advanced form, plus an SQL Query, which selects and iterates over all records. Those records will be loaded at the same time.
      • Delete form: any form can be used as a form to :ref:`delete-record`.
    • Form mode: The parameter 'r' (given via URL or via SIP) decide if the form is in mode:

      • New:

        • Missing parameter 'r' or 'r=0'
        • On form load, no record is displayed.
        • Saving the form creates a new primary record.
        • E.g.: http://example.com/index.php?id=home&form=Person or http://example.com/index.php?id=home&form=Person&r=0
      • Edit:

        • Parameter 'r>0'
        • On form load, the specified record (<tablename>.id= <r>) will be loaded and displayed.
        • Saving the form will update the existing record.
        • E.g.: http://example.com/index.php?id=home&form=Person&r=123
      • Providing additional parameter:

        Often, it is necessary to store additional, for the user not visible, parameter in a record. See :ref:`form-magic`.

    • Display a form:

      • Create a QFQ tt_content record on a Typo 3 page.
      • Inside the QFQ record: form = <formname>. E.g.:
        • Static: form = Person
        • Dynamic 1: form = {{form:SE}} (the left form is a keyword for QFQ, the right form is a variable name)
        • Dynamic 2: form = {{SELECT f.name FROM Form AS f WHERE f.id=...}} (the left form is a keyword for QFQ, the right form is a variable name)
      • With the Dynamic option, it's easily possible to use one Typo3 page and display different forms on that specific page.
    • If a form is edited using the JSON form editor then a backup of the previous version is saved. See :ref:`formAsFile`.

    Form process order

    Depending on form load / save or record delete, different tasks are performed. Processing is divided into:

    • Native FormElements like: input, select list, checkbox, radio, ....
      • upload elements are categorized as native FormElement, but will be processed later.
      • pill, fieldset and subrecord elements are only processed during form load, they do not impact save or delete.
    • Action FormElement like before..., after..., sendmail ...

    Each FormElement has an order.

    Native FormElements which 'name':

    • corresponds to a column in the form primary table: are grouped together in one insert or update query.
    • do not correspond to a column in the primary table: needs an explicit defined Action FormElement to be handled.

    FormElement processing order:

    Images/FormProcess.png

    Record locking

    Support for record locking is given with mode:

    • exclusive: user can't force a write.
      • Including a timeout (default 15 mins recordLockTimeoutSeconds in :ref:`configuration`) for maximum lock time.
    • advisory: user is only warned, but allowed to overwrite.
    • none: no bookkeeping about locks.

    Details:

    • For 'new' records (r=0) there is no locking at all.
    • The record locking protection is based on the tablename and the record id. Different Forms, with the same primary table, will be protected by record locking.
    • Action-FormElements updating non primary table records are not protected by 'record locking': the QFQ record locking is NOT 100%.
    • The 'record locking' mode will be specified per Form. If there are multiple Forms with different modes, and there is already a lock for a tablename / record id pair, the most restrictive will be applied.
    • A user opens a form: starting with the first change of content, a record lock will be acquired in the background. If the lock is denied (e.g. another user already owns a lock on the record) an alert is shown. This means: the lock timeout counts from the first change, not from the last modification on the form.
    • If a timeout expires, the lock becomes invalid. During the next change in a form, the lock is acquired again.
    • A lock is assigned to a record of a table. Multiple forms, with the same primary table, uses the same lock for a given record.
    • If a user tries to delete a record and another user already owns a lock on that record, the delete action is denied.
    • If there are different locking modes in multiple forms, the most restricting mode applies for the current lock.
    • If the same user opens the same recording in different tabs or browsers, the user has the possibility to skip a lock.

    Exclusive

    An existing lock on a record forbids any write action on that record. Exception: locks owned by the same user might be overwritten.

    Advisory

    An existing lock on a record informs the user that another user is currently working on that record. Nevertheless, writing is allowed.

    None

    No locking at all.

    Comment- and space-character

    The following applies to the fields Form.parameter and FormElement.parameter:

    • Lines will be trimmed - leading and trailing spaces will be removed.
    • If a leading and/or trailing space is needed, escape it: \ hello world \ > ' hello world '.
    • Lines starting with a '#' are treated as a comment and will not be parsed. Such lines are treated as 'empty lines'.
    • The comment sign can be escaped with \ .

    Form Settings

    Name Description
    Name Unique and speaking name of the Form. Form will be identified by this name. Use only '[a-zA-Z0-9._+-]'. form-name
    Title Title, shown on/above the form. form-title
    Note Personal editor notes. form-note
    Table Primary table of the form. form-tablename
    Primary Key Primary key of the indicated table. Only needed if != 'id'. form-primary-key
    Required Parameter NEW Name of required SIP parameter to create a new record (r=0), separated by comma. '#' as comment delimiter. See :ref:`form-requiredParameter`
    Required Parameter EDIT Name of required SIP parameter to edit an existing record (r>0), separated by comma. '#' as comment delimiter. See :ref:`form-requiredParameter`
    Permit New 'sip, logged_in, logged_out, always, never' (Default: sip): See :ref:`form-permitNewEdit`
    Permit Edit 'sip, logged_in, logged_out, always, never' (Default: sip): See :ref:`form-permitNewEdit`
    Permit REST See :ref:`restApi`
    Escape Type Default See :ref:`variable-escape`.
    Show button 'new, delete, close, save' (Default: 'new,delete,close,save'): Shown named buttons in the upper right corner of the form. See :ref:`form-showButton`
    Forward Mode 'auto | close | no | url | url-skip-history | url-sip | url-sip-skip-history' (Default: auto): See :ref:`form-forward`.
    Forward (Mode) Page
    1. URL / Typo3 page slug or b) Forward Mode (via '{{...}}') or combination of a) & b). See :ref:`form-forward`.
    labelAlign Label align (default/left/center/right)/ Default: 'default' (defined by Config). form-label-align
    Parameter Misc additional parameters. See :ref:`form-parameter`.
    BS Label Columns The bootstrap grid system is based on 12 columns. The sum of bsLabelColumns, bsInputColumns and bsNoteColumns should be 12. These values here are the base values for all FormElements. Exceptions per FormElement can be specified per FormElement. Default: label=col-md-3, input=col-md-6, note=col-md-3. See :ref:`form-layout`.
    BS Input Columns
    BS Note Columns
    multiMode NOT IMPLEMENTED - 'none, horizontal, vertical' (Default 'none')
    multiSql NOT IMPLEMENTED - Optional. SQL Query which selects all records to edit.
    multiDetailForm NOT IMPLEMENTED - Optional. Form to open, if a record is selected to edit (double click on record line)
    multiDetailFormParameter NOT IMPLEMENTED - Optional. Translated Parameter submitted to detail form (like subrecord parameter)
    multiFormWrap By default (if empty) wraps the form in a HTML table. Alternative is to use CSS grid. See :ref:`multi-form-grid`.
    multiFormCellWrap By default (if empty) wraps each input in <td>. If 'multiFormWrap' is given but multiFormCellWrap is empty, than the default is <div>. See :ref:`multi-form-grid`.

    permitNew & permitEdit

    Depending on r, the following access permission will be taken:

    • r=0 - permitNew
    • r>0 - permitEdit
    Option Description
    sip The parameter 'form' and 'r' must be supplied via SIP or hard coded in the QFQ tt_content record.
    logged_in The form will only be shown if the current User is logged in as a FE User
    logged_out The form will only be shown if the current User is not logged in as a FE User
    always No access restriction, the form will always be shown
    never The form will never be shown
    • sip
      • is always the preferred way. With 'sip' it's not necessary to differ between logged in or not, cause the SIP only exist and is only valid, if it's created via QFQ/report earlier. This means 'creating' the SIP implies 'access granted'. The grant will be revoked when the QFQ session is destroyed - this happens when a user logs out or the web browser is closed.
    • logged_in / logged_out: for forms which might be displayed without a SIP, but maybe on a protected or even unprotected page. The option is probably not often used.
    • always: such a form is always allowed to be loaded.
      • permitNew=always: Public accessible forms (e.g. for registration) will allow users to fill and save the form.
      • permitEdit=always: Public accessible forms will allow users to update existing data. This is dangerous, cause the URL parameter (recordId) 'r' might be changed by the user (URL manipulating) and therefore the user might see and/or change data from other users. The option is probably not often used.
    • never: such a form is not allowed to be loaded.
      • permitNew=never: Public accessible forms. It's not possible to create new records.
      • permitEdit=none: Public accessible forms. It's not possible to update records.

    Required Parameter New|Edit

    Comma separated list of variable names. On form load, an error message will be shown in case of missing parameters. The parameters must be given by SIP.

    The list of required parameter has to be defined for New (r=0, create a new record) and for Edit (r>0, edit existing record).

    Optional a comment might be attached after the parameter definition.

    E.g.:

    New: grId, pId # Always specify a person, grId2
    Edit: pId

    showButton

    Display or hide the button new, delete, close, save.

    • new: Creates a new record. If the form needs any special parameter via SIP or Client (=browser), hide this 'new' button - the necessary parameter are not provided.
    • delete: This either deletes the current record only, or (if defined via action FormElement 'beforeDelete' ) any specified subrecords.
    • close: Close the current form. If there are changes, a popup opens and ask to save / close / cancel. The last page from the history will be shown.
    • save: Save the form.
    • Default: show all buttons.

    Forward: Save / Close

    Forward (=forwardMode)

    After the user presses Save, Close, Delete or New, different actions are possible where the browser redirects to.

    • auto (default) - the QFQ browser Javascript logic, decides to stay on the page or to force a redirection to a previous page. The decision depends on:
      • Close goes back (feels like close) to the previous page. Note: if there is no history, QFQ won't close the tab, instead a message is shown.
      • Save stays on the current page.
    • close - goes back (feels like close) to the previous page. Note: if there is no history, QFQ won't close the tab, instead a message is shown.
    • no - no change, the browser remains on the current side. Close does not close the page. It just triggers a save if there are modified data.
    • url - the browser redirects to the URL or T3 page named in Forward URL / Page. Independent if the user presses save or close.
    • url-skip-history - same as url, but the current location won't saved in the browser history.
    • url-sip - like url, but any given parameter will be SIP encoded. Only useful if url points to current web instance.
    • url-sip-skip-history - like url-sip, but skips the Browser history.

    Only with Forward == url | url-skip-history, the definition of Forward URL / Page becomes active.

    Forward URL / Page (=forwardPage)

    Format: [<url>] or [<mode>|<url>]

    • <url>:
      • http://www.example.com/index.html?a=123#bottom
      • website.html?a=123#bottom
      • <T3 page slug>&a=123#bottom, ?id=<T3 page id>&a=123#bottom
      • {{SELECT ...}}
      • <mode>|<url>
    • <mode> - Valid keywords are as above: auto|close|no|url|url-skip-history|url-sip|url-sip-skip-history

    Specifying the mode in forwardPage overwrites formMode (but only if formMode is url...).

    Also regular QFQ statements like {{var}} or {{SELECT ...}} are possible in forwardPage. This is useful to dynamically redirect to different targets, depending on user input or any other dependencies.

    If a forwardMode 'url...' is specified and there is no forwardPage, QFQ falls down to auto mode.

    On a form, the user might click 'save' or 'save,close' or 'close' (with modified data this leads to 'save,close'). The CLIENT submit_reason shows the user action:

    • {{submit_reason:CE:alnumx}} = save or save,close

    Example forwardPage

    • {{SELECT IF('{{formModeGlobal:S}}'='requiredOff', 'no', 'auto') }}
    • {{SELECT IF('{{submit_reason:CE:alnumx}}'='save', 'no', 'url'), '|http://example.com' }}

    Type: combined dynamic mode & URL/page

    Syntax: forwardPage=<mode>|<page>

    • forwardPage={{SELECT IF(a.url='','no','url'), '|', a.url FROM Address AS a }}

    Form.parameter

    • The following parameter are optional.
    • Each parameter has to be on a single line.
    • If a parameter is defined multiple time, the last one is the final one.
    • Comment lines have to start with #.
    Name Type Description
    dbIndex int Database credential index, given via :ref:`config-qfq-php` to let the current Form operate on the database.
    bsColumns string Wrap the whole form in '<div class="col-md-.. col-lg-..">. See :ref:`bs-custom-field-width`.
    maxVisiblePill int Show pills upto <maxVisiblePill> as button, all further in a drop-down menu. Eg.: maxVisiblePill=3.
    class string HTML div with given class, surrounding the whole form. Eg.: class=container-fluid.
    classTitle string CSS class inside of the title div. Default 'qfq-form-title'.
    classPill string HTML div with given class, surrounding the pill title line.
    classBody string HTML div with given class, surrounding all FormElement.
    extraDeleteForm string Name of a form which specifies how to delete the primary record and optional slave records.
    data-pattern-error string Pattern violation: Text for error message used for all FormElements of current form.
    data-required-error string Required violation: Text for error message used for all FormElements of current form.
    data-match-error string Match violation: Text for error message used for all FormElements of current form.
    data-error string If none specific is defined: Text for error message used for all FormElements of current form.
    buttonOnChangeClass string Color for save button after user modified some content or current form. E.g.: 'btn-info alert-info'.
    ldapServer string FQDN Ldap Server. E.g.: directory.example.com.
    ldapBaseDn string E.g.: ou=Addressbook,dc=example,dc=com.
    ldapAttributes string List of attributes to fill STORE_LDAP with. E.g.: cn, email.
    ldapSearch string E.g.: (mail={{email::alnumx:l}})
    ldapTimeLimit int Maximum time to wait for an answer of the LDAP Server.
    typeAheadLdap   Enable LDAP as 'Typeahead' data source.
    typeAheadLdapSearch string Regular LDAP search expression. E.g.: (|(cn=*?*)(mail=*?*))
    typeAheadLdapValuePrintf string Value formatting of LDAP result, per entry. E.g.: '%s / %s / %s', mail, room number, telephone number
    typeAheadLdapIdPrintf string Key formatting of LDAP result, per entry. E.g.: '%s', mail
    typeAheadLdapSearchPerToken   Split search value in token and OR-combine every search with the individual tokens.
    typeAheadLimit int Maximum number of entries. The limit is applied to the server (LDAP or SQL) and the Client.
    typeAheadMinLength int Minimum number of characters which have to typed to start the search.
    mode string The value readonly will activate a global readonly mode of the form - the user can't change any data. See :ref:`form-mode-global`
    activateFirstRequiredTab digit 0: off, 1: (default) - with formModeGlobal=requiredOffButMark bring pill to front on save. See :ref:`form-mode-global`
    enterAsSubmit digit 0: off, 1: Pressing enter in a form means save and close. Takes default from :ref:`configuration`.
    submitButtonText string Show a save button at the bottom of the form, with <submitButtonText> . See :ref:`submitButtonText`.
    saveButtonActive   0: off, 1: Make the 'save'-button active on Form load (instead of waiting for the first user change). The save button is still 'gray' (record not dirty), but the user can click 'save'.
    saveButtonText string Overwrite default from :ref:`configuration`
    saveButtonTooltip string Overwrite default from :ref:`configuration`
    saveButtonClass string Overwrite default from :ref:`configuration`
    saveButtonGlyphIcon string Overwrite default from :ref:`configuration`
    closeButtonText string Overwrite default from :ref:`configuration`
    closeButtonTooltip string Overwrite default from :ref:`configuration`
    closeButtonClass string Overwrite default from :ref:`configuration`
    closeButtonGlyphIcon string Overwrite default from :ref:`configuration`
    deleteButtonText string Overwrite default from :ref:`configuration`
    deleteButtonTooltip string Overwrite default from :ref:`configuration`
    deleteButtonClass string Overwrite default from :ref:`configuration`
    deleteButtonGlyphIcon string Overwrite default from :ref:`configuration`
    newButtonText string Overwrite default from :ref:`configuration`
    newButtonTooltip string Overwrite default from :ref:`configuration`
    newButtonClass string Overwrite default from :ref:`configuration`
    newButtonGlyphIcon string Overwrite default from :ref:`configuration`
    extraButtonInfoClass string Overwrite default from :ref:`configuration`
    extraButtonInfoMinWidth string See :ref:`extraButtonInfo`
    fillStoreVar string Fill the STORE_VAR with custom values. See :ref:`STORE_VARS`.
    showIdInFormTitle string Overwrite default from :ref:`configuration`
    formSubmitLogMode string Overwrite default from :ref:`configuration`
    sessionTimeoutSeconds int Overwrite default from :ref:`configuration`. See :ref:`sessionTimeoutSeconds`.
    maxFileSize int Overwrite default from :ref:`configuration`
    requiredPosition int See :ref:`requiredPosition`
    clearMe 0 / 1 Overwrite default from :ref:`configuration`. Show a small 'x' in every input or textarea to clear field.
    rememberLastPill 0 / 1 Overwrite default from :ref:`configuration`. On form load, bring last used pill to front
    doNotLogColumn string Overwrite default from :ref:`configuration`. Comma separated list of Form-Element names.
    fieldsetClass string Overwrite default from :ref:`configuration`.
    btnPreviousNextSql string Query that selects records which are then accessible by the previous/next buttons. See :ref:`btnPreviousNextSql`
    btnPreviousNextLoop digit 0: off, 1: Allow to loop through the records (from last to first and vice versa).
    btnPreviousNextWrap string Wrap the buttons in custom HTML. Default: '<span class="pull-right"><div class="btn-group" role="group">'
    • Example in field Form.parameter:

      maxVisiblePill = 5
      class = container-fluid
      classBody = qfq-form-right

    submitButtonText

    If specified and non empty, display a regular submit button at the bottom of the page with the given text. This gives the form a ordinary HTML-form look 'n' feel. With this option, the standard buttons on the top right border should be hidden to not confuse the user.

    • Optional.
    • Default: Empty

    class

    • Optional.
    • Default: container
    • Any CSS class name(s) can be specified.
    • Check typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css for predefined classes.
    • Typical use: adjust the floating rules of the form.

    classPill

    • Optional.
    • Default: qfq-color-grey-1
    • Any CSS class name(s) can be specified.
    • Check typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css for predefined classes.
    • Typical use: adjust the background color of the pill title area.
    • Predefined background colors: qfq-color-white, qfq-color-grey-1 (dark), qfq-color-grey-2 (light), qfq-color-blue-1 (dark), qfq-color-blue-2. (light)
    • classPill is only visible on forms with container elements of type 'Pill'.

    classBody

    • Optional.
    • Default: qfq-color-grey-2
    • Any CSS class name(s) can be specified.
    • Check typo3conf/ext/qfq/Resources/Public/Css/qfq-bs.css for predefined classes.
    • Typical use:
      • adjust the background color of the FormElement area.
      • make all form labels right align: qfq-form-right.
    • Predefined background colors: qfq-color-white, qfq-color-grey-1 (dark), qfq-color-grey-2 (light), qfq-color-blue-1 (dark), qfq-color-blue-2. (light)

    extraDeleteForm

    Depending on the database definition, it might be necessary to delete the primary record and corresponding slave records.

    To not repeat such 'slave record delete definition', an 'extraDeleteForm' can be specified. If the user opens a record in a form and clicks on the 'delete' button, a defined 'extraDeleteForm'-form will be used to delete primary and slave records instead of using the current form.

    E.g. if there are multiple different forms to work on the same table, all of theses forms might reference to the same 'extraDeleteForm'-form. This simplifies the maintenance.

    The 'extraDeleteForm' parameter might be specified for a 'form' and/or for 'subrecords'

    See also: :ref:`delete-record`.

    btnPreviousNextSql

    Generates two navigation buttons in the form title that link to the previous/next record.

    Records are selected and ordered by a query which uses the columns 'id', 'btnPrevious' (optional), 'btnNext' (optional) and 'btnCurrent' (optional).

    Optional columns can be used to style the buttons using the AS _link notation. 'bntCurrent' generates a third button in between the other two. Example:

    # Only arrows, no text.
    btnPreviousNextSql = {{!SELECT adr.id AS id FROM Address AS adr WHERE adr.personId={{personId:R}} }}
    
    # Text
    btnPreviousNextSql = {{!SELECT adr.id AS id
                                   , CONCAT('p:{{pageSlug:T}}?form={{form:S}}&r=', adr.id, '|s|b|t:Previous: ', adr.city) AS btnPrevious
                                   , CONCAT('p:{{pageSlug:T}}?form={{form:S}}&r=', adr.id, '|s|b|t:Next: ', adr.city) AS btnNext
                             FROM Address AS adr
                             WHERE adr.personId={{personId:R}} }}
    • btnPreviousNextLoop:
      • 0: no loop.
      • 1: Allow to loop through the records (from last to first and vice versa).
    • btnPreviousNextWrap: Wrap the buttons in custom HTML. Default: '<span class="pull-right"><div class="btn-group" role="group">'|

    Form mode global

    A form can be operated in modes: standard | readonly | requiredOff | requiredOffButMark.

    Mode standard is given if none of the others are defined.

    The mode is given via (in this priority):

    • Via STORE_USER: {{formModeGlobal:U}}
    • Via STORE_SIP: {{formModeGlobal:S}}
    • Via Form: form.parameter.formModeGlobal=...
    Mode
    • standard:
      • The form will behave like defined in the form editor.
      • Missing required values will a) be indicated and b) block saving the record.
    • readonly: all FormElement of the whole form are temporarily in readonly mode.
      • Fast way to display the form data, without a possibility for the user to change any data of the form.
      • The mode will be be inherited to all subforms.
    • requiredOff:
      • All FormElement with mode=required, will be handled as mode=show.
      • The user can save the form without filling all required inputs!
      • Required inputs are indicated by a red star - missing values won't be complained.
    • requiredOffButMark:
      • All FormElement with mode=required, will be handled as mode=show.
      • The user can save the form without filling all required inputs!
      • Missing required inputs will be marked:
        • On lost focus.
        • When the user saves the record.
          • After saving the record, by default the first pill with a missing input comes to front.
          • This behaviour can be switch on/off with form.parameter.activateFirstRequiredTab=0
    Extra

    Via :ref:`STORE_VARS` the variable {{allRequiredGiven:V}} shows, if the form has been filled completely - independent of the mode. The variable is only accessible during form save.

    Usage example

    Readonly

    Code: SELECT 'p:{{pageSlug}}?form=person&r=1&formModeGlobal=readonly|s|t:View|s|b' AS _link

    • The form is called with SIP parameter formModeGlobal=readonly or form.parameter.mode=readonly.
    • The user can't change any data.

    Readonly system wide

    Code (somewhere): SELECT 'requiredOff' AS '_=formModeGlobal'

    Code: SELECT 'p:{{pageSlug}}?form=person&r=1|s|t:View|s|b' AS _link

    • The STORE_USER variable is set formModeGlobal=readonly.
    • All forms will be shown in readonly mode - fast option to give a user access to the website, without the possibility to change any data.

    Draft Mode 1

    Code: SELECT 'p:{{pageSlug}}?form=person&r=1&formModeGlobal=requiredOff|s|t:View|s|b' AS _link

    • A form has one or more FormElement with 'fe.type=required'.
    • Opening the form with formModeGlobal=requiredOff will allow the user to save the form, even if not all FE.type=required elements are given. This can be called 'draft' mode.
    • Opening the form without formModeGlobal (that's the default), forces the user to fill out all FE.type=required fields. This can be called 'final submit' mode.

    Draft Mode 2

    Code: SELECT 'p:{{pageSlug}}?form=person&r=1&formModeGlobal=requiredOff|s|t:View|s|b' AS _link

    • A form has one or more FormElement with 'fe.type=required'.

    • Calling the form with formModeGlobal=requiredOff will allow the user to save the form, even if not all FE.type=required elements are given.

    • Define an FE-Action 'afterSave', and do some action on {{allRequiredGiven:V0}} like:

      {{UPDATE <table> SET dataValid={{allRequiredGiven:V0}} WHERE id={{id:R}} }}
    • In the application logic, open the next process step if all data is given by evaluating dataValid.

    FormElements

    • Each form contains one or more FormElement.
    • The FormElements are divided in three categories:
      • :ref:`class-container`
      • :ref:`class-native`
      • :ref:`class-action`
    • Ordering and grouping: Native FormElements and Container-Elements (both with feIdContainer=0) will be ordered by 'ord'.
    • Inside of a container, all nested elements will be displayed.
    • Technical, it's not necessary to configure a FormElement for the primary index column id.
    • Additional options to a FormElement will be configured via the FormElement.parameter field (analog to Form.parameter for Forms ).
      • See also: :ref:`comment-space-character`

    Class: Container

    • Pills are containers for 'fieldset' and / or 'native' FormElements.
    • Fieldsets are containers for 'native' FormElements.
    • TemplateGroups are containers for 'fieldset' and / or 'native' FormElements.

    Type: fieldset

    • Native FormElements can be assigned to a fieldset.
    • FormElement settings:
      • name: technical name, used as HTML identifier.
      • label: Shown title of the fieldset.
      • mode:
        • show: all child elements will be shown.
        • required: all child elements are also set to 'required'.
        • readonly: technically it's like HTML/CSS disabled.
        • hidden:
          • The fieldset is invisible.
          • The FormElements within the fieldset still exist, but are not reachable for the user via UI.
      • parameter:
        • fieldsetClass: Overwrite default from Form.parameter.fieldsetClass

    Type: pill (tab)

    • Pill is synonymous for a tab and looks like a tab.
    • If there is at least one pill defined:
      • every native FormElement needs to be assigned to a pill or to a fieldset.
      • every fieldset needs to be assigned to a pill.
    • Mode:
      • show: all child elements will be shown.
      • required: same as 'show'. This mode has no other meaning than 'show'.
      • readonly: technically it's like HTML/CSS disabled.
        • The pill title is shown, but not clickable.
        • The FormElements on the pill still exist, but are not reachable for the user via UI.
      • hidden:
        • The pill is invisible.
        • The FormElements on the pill still exist, but are not reachable for the user via UI.
      • Note: Independent of the mode, all child elements are always rendered and processed by the client/server.
    • Pills are 'dynamicUpdate' aware. title and mode are optional recalculated during 'dynamicUpdate'.
    • FormElement settings:
      • name: technical name, used as HTML identifier.
      • label: Label shown on the corresponding pill button or inside the drop-down menu.
      • mode:
        • show, required: regular mode. The pill will be shown.
        • readonly: the pill and it's name is visible, but not clickable.
        • hidden: the pill is not shown at all.
      • modeSql:
      • type: pill
      • feIdContainer: 0 - Pill's can't be nested.
      • tooltip: Optional tooltip on hover. Especially helpful if the pill is set to readonly.
      • parameter:
        • maxVisiblePill: <nr> - Number of Pill-Buttons shown. Undefined means unlimited. Excess Pill buttons will be displayed as a drop-down menu.

    Type: templateGroup

    TemplateGroups will be used to create a series of grouped (by the given templateGroup) FormElements.

    FormElements can be assigned to a templateGroup. These templateGroup will be rendered upto n-times. On 'form load' only a single (=first) copy of the templateGroup will be shown. Below the last copy of the templateGroup an 'add'-button is shown. If the user click on it, an additional copy of the templateGroup is displayed. This can be repeated up to templateGroup.maxLength times. Also, the user can 'remove' previously created copies by clicking on a remove button near beside every templateGroup. The first copy of a templateGroup can't be removed.

    • FormElement settings:
      • label: Shown in the FormElement-editor container field.
      • maxLength: Maximum number of copies of the current templateGroup. Default: 5.
      • bsLabelColumn, bsInputColumn, bsNoteColumn: column widths for row with the 'Add' button.
      • parameter:
        • tgAddClass: Class of the 'add' button. Default: btn btn-default.
        • tgAddText: Text shown on the button. Default: Add.
        • tgRemoveClass: Class of the 'remove' button. Default: btn btn-default.
        • tgRemoveText: Text shown on the button. Default: Remove.
        • tgClass: Class wrapped around every copy of the templateGroup. E.g. the class qfq-child-margin-top adds a margin between two copies of the templateGroup. Default: empty

    Multiple templateGroups per form are allowed.

    The name of the native FormElements, inside the templateGroup, which represents the effective table columns, uses the placeholder %d. E.g. the columns grade1, grade2, grade3 needs a FormElement.name = grade%d. The counting will always start with 1. The placeholder %d can also be used in the FormElement.label

    Example of styling the Add/ Delete Button: :ref:`example_class_template_group`

    Column: primary record

    If the columns <name>%d are real columns on the primary table, saving and delete (=empty string) are done automatically. E.g. if there are up to five elements grade1, ..., grade5 and the user inputs only the first three, the remaining will be set to an empty string.

    Column: non primary record

    Additional logic is required to load, update, insert and/or delete slave records.

    Load

    On each native FormElement of the templateGroup define an SQL query in the FormElement.value field. The query has to select all values of all possible existing copies of the FormElement - therefore the exclamation mark is necessary. Also define the order. E.g. FormElement.value:

    {{!SELECT street FROM Address WHERE personId={{id}} ORDER BY id}}
    Insert / Update / Delete

    Add an action record, type='afterSave', and assign the record to the given templateGroup.

    In the parameter field define:

    slaveId = {{SELECT id FROM Address WHERE personId={{id}} ORDER BY id LIMIT %D,1}}
    sqlHonorFormElements = city%d, street%d
    sqlUpdate = {{UPDATE Address SET city='{{city%d:FE:alnumx:s}}', street='{{street%d:FE:alnumx:s}}'  WHERE id={{slaveId}} LIMIT 1}}
    sqlInsert = {{INSERT INTO Address (`personId`, `city`, `street`) VALUES ({{id}}, '{{city%d:FE:alnumx:s}}' , '{{street%d:FE:alnumx:s}}') }}
    sqlDelete = {{DELETE FROM Address WHERE id={{slaveId}} LIMIT 1}}

    The slaveId needs attention: the placeholder %d starts always at 1. The LIMIT directive starts at 0 - therefore use %D instead of %d, cause %D is always one below %d - but can only be used on the action element.

    Class: Native

    Fields:

    FormElement.value

    By default this field is empty: QFQ will fill it with the corresponding existing column value on form load. For a customized default value define:

    {{SELECT IF('{{column:RE}}'='','custom default', '{{column:R}}') }}

    For non primary records, this is the place to load an existing value. E.g. we're on a 'Person' detail form and would like to edit, on the same form, a corresponding person email address (which is in a separate table):

    {{SELECT a.email FROM Address AS a WHERE a.pId={{id:R0}} ORDER BY a.id LIMIT 1}}

    Report syntax can also be used, see :ref:`report-notation`.

    FormElement: 'Report' notation

    The FE fields 'value' and 'note' understand the :ref:`Report` syntax. Nested SQL queries as well as links with SIP encoding are possible. To distinguish between 'Form' and 'Report' syntax, the first line has to be #!report:

    #!report
    
    10.sql = SELECT ...
    
    20 {
      sql = SELECT ...
      5.sql = SELECT ...
    }

    FormElement.parameter

    • The following parameter are optional.
    • Each parameter has to be on a single line.
    • If a parameter is defined multiple time, the last one is the final one.
    • Comment lines have to start with #.
    • See also documentation at specific FormElement.
    Name Note
    acceptZeroAsRequired 0|1 - Accept a '0' as a valid input. Default '0' (=0 is not a valid input)
    autofocus See :ref:`input-option-autofocus`
    capture, accept, maxFileSize, fileDestination, fileTrash, fileTrashText, fileReplace, autoOrient, autoOrientCmd, autoOrientMimeType, chmodFile, chmodDir, slaveId, sqlBefore, sqlInsert, sqlUpdate, sqlDelete, sqlAfter, importToTable, importToColumns, importRegion, importMode, importType, importNamedSheetsOnly, importSetReadDataOnly, importListSheetNames, See :ref:`input-upload`
    checkBoxMode checked unchecked label2 itemList emptyHide emptyItemAtStart emptyItemAtEnd buttonClass See :ref:`input-checkbox`, :ref:`input-radio`, :ref:`input-select`
    dateFormat yyyy-mm-dd / dd.mm.yyyy
    data-pattern-error Pattern violation: Text for error message
    data-required-error Required violation: Text for error message
    data-match-error Match violation: Text for error message
    data-error Violation of 'check-type': Text for error message
    decimalFormat [precision,scale] Limits and formats input to a decimal number with the specified precision and scale. If no precision and scale are specified, the decimal format is pulled from the table definition.
    htmlAfter HTML Code wrapped after the complete FormElement
    htmlBefore HTML Code wrapped before the complete FormElement
    extraButtonLock [0|1] Show a 'lock' on the right side of the input element. See :ref:`extraButtonLock`
    extraButtonPassword [0|1] Show an 'eye' on the right side of the input element. See :ref:`extraButtonPassword`
    extraButtonInfo Text. Show an 'i' on the right side of the input element. See :ref:`extraButtonInfo`
    extraButtonInfoClass By default empty. Specify any class to be assigned to wrap extraButtonInfo
    extraButtonInfoMinWidth See :ref:`extraButtonInfo`
    editor-plugins, editor-toolbar, editor-statusbar, editor-forced_root_block, editor-extended_valid_elements, editor-content_css, editor-relative_urls, editorType, codemirror-mode, codemirror-lineNumbers, codemirror-lineWrapping, codemirror-tabSize, codemirror-styleActiveLine, codemirror-matchBrackets, codemirror-autoCloseBrackets, codemirror-keywords-qfq-base See :ref:`input-editor`
    fileButtonText Overwrite default 'Choose File'
    fillStoreVar Fill the STORE_VAR with custom values. See :ref:`STORE_VARS`.
    form, page, title, extraDeleteForm, detail, new, subrecordTableClass, subrecordTableAttribute, subrecordColumnTitleEdit, subrecordColumnTitleDelete, subrecordAppendSql, subrecordAppendClass, subrecordAppendForm, subrecordAppendExtraDeleteForm, subrecordAppendEmptyText, orderInterval, dndTable, orderColumn See :ref:`subrecord-option`
    min s/d/n

    Minimum and/or maximum allowed values for input field. Can be used for numbers, dates, or strings.

    Always use the international format 'yyyy-mm-dd[ hh:mm[:ss]]

    max s/d/n
    processReadOnly [0|1] By default FE's with type='readonly' are not processed during 'save'. This option forces to process them during 'save' as well. See :ref:`processReadOnly`.
    retype, retypeLabel, retypeNote See :ref:`retype`
    characterCountWrap, hideZero inputType, step, textareaResize, htmlAllow See :ref:`input-text`
    emptyMeansNull Applies to all native FormElement types (input, checkbox, radio, select, ...). See :ref:`input-text`
    showSeconds 0|1 - Shows the seconds on form load. Default: 0
    showZero 0|1 - Empty timestamp: '0'(default) - nothing shown, '1' - the string '0000-00-00 00:00:00' is displayed
    timeIsOptional 0|1 - Used for datetime input. 0 (default): Time is required - 1: Entering a time is optional (defaults to 00:00:00 if none entered).
    typeAheadLimit, typeAheadInitialSuggestion, typeAheadMinLength, typeAheadSql, typeAheadSqlPrefetch, typeAheadPedantic See :ref:`input-typeahead`
    typeAheadTag, typeAheadGlueInsert, typeAheadGlueDelete, typeAheadTagInsert, typeAheadTagDelimiter See :ref:`type_ahead_tag`
    wrapRow If specified, skip default wrapping (<div class='col-md-?'>). Instead the given string is used.
    wrapLabel
    wrapInput
    wrapNote
    trim By default, whitespace is trimmed. To disable, use 'trim=none'. You can also specify custom trim characters: 'trim=\ ' only trims spaces.
    sqlValidate, expectRecords, alert, qfqLog, requiredList See :ref:`sqlValidate`
    dataReference Optional. See :ref:`applicationTest`
    requiredPosition See :ref:`requiredPosition`.
    indicateRequired By default, indicate 'required' by an asterisk. indicateRequired=0 will hide the asterisk. Default: 1
    minWidth See :ref:`checkboxRadioMinWidth`.
    clearMe 0 (off)|1(on) - Overwrite default from Form.parameter.clearMe or :ref:`configuration`. Show a small 'x' in input or textarea fields to clear the input.
    defaultValue Set custom default value. If not set, db column default value will be taken.
    • s/d/n: string or date or number.

    slaveId, sqlBefore, sqlAfter, ...

    See :ref:`slave-id`

    Native FormElements

    • Like 'input', 'checkbox', ...
    autofocus

    The first FormElement with this attribute will get the focus after form load. If there is no such attribute given to any FormElement, the attribute will be automatically assigned to the first editable FormElement.

    To disable 'autofocus' on a form, set 'autofocus=0' on the first editable FormElement.

    Note: If there are multiple pills defined on a form, only the first pill will be set with 'autofocus'.

    extraButtonLock
    • The user has to click on the lock, before it's possible to change the value. This will protect data against unwanted modification.
    • After Form load, the value is shown, but not editable.
    • Shows a 'lock' on the right side of an input element of type text, date, time or datetime.
    • This option is not available for FormElements with mode=readonly.
    • There is no value needed for this parameter.
    extraButtonPassword
    • The user has to click on the eye (un-hide) to see the value.
    • After Form load, the data is hidden by asterisk.
    • Shows an 'eye' on the right side of an input element of type text, date, time or datetime.
    • There is no value needed for this parameter.
    extraButtonInfo
    • After Form load, the info button/icon is shown but the information message is hidden.
    • The user has to click on the info button/icon to see an additional message.
    • The value of this parameter is the text shown to the user.
    • Shows an info button/icon, depending of extraButtonInfoPosition in :ref:`configuration`
      • auto, depending on FormElement type:
        • on the right side of an input element for type text, date, time or datetime,
        • below the FormElement for all other types.
      • below: below the FormElement for all types.
    • extraButtonInfoMinWidth: default is 250 and defines a minimal width.
    • For FormElement with mode below, a span element with the given class in extraButtonInfoClass (FE, F, :ref:`configuration`) will be applied. E.g. this might be pull-right to align the info button/icon on the right side below the input element.
    processReadOnly

    By default FormElements with mode='readonly' are not processed. In most use cases, this is the expected behaviour: An element which can't be modified by the user, should not be written during a save. Exceptions might be given, like: FE is enabled by dynamic update, modified by the user, deactivated again and than the record is saved.

    Checkbox / Radio: minWidth

    Checkbox and Radio Elements, shown in plain horizontal mode, receives a minWidth to align them. The default is 80px and might be defined per Form or per FormElement.

    Required Position

    By default, input elements with Mode=required will be displayed with a 'red asterisk' right beside the label. The position of the 'red asterisk' can be chosen via the parameter field:

    requiredPosition = label-left|label-right|input-left|input-right|note-left|note-right