.. _form_dissection: Dissection of an entity form ---------------------------- This is done (again) with a vanilla instance of the `tracker`_ cube. We will populate the database with a bunch of entities and see what kind of job the automatic entity form does. .. _`tracker`: https://forge.extranet.logilab.fr/cubicweb/cubes/tracker Populating the database ~~~~~~~~~~~~~~~~~~~~~~~ We should start by setting up a bit of context: a project with two unpublished versions, and a ticket linked to the project and the first version. .. sourcecode:: python >>> p = rql('INSERT Project P: P name "cubicweb"') >>> for num in ('0.1.0', '0.2.0'): ... rql('INSERT Version V: V num "%s", V version_of P WHERE P eid %%(p)s' % num, {'p': p[0][0]}) ... >>> t = rql('INSERT Ticket T: T title "let us write more doc", T done_in V, ' 'T concerns P WHERE V num "0.1.0"', P eid %(p)s', {'p': p[0][0]}) >>> commit() Now let's see what the edition form builds for us. .. sourcecode:: python >>> cnx.use_web_compatible_requests('http://fakeurl.com') >>> req = cnx.request() >>> form = req.vreg['forms'].select('edition', req, rset=rql('Ticket T')) >>> html = form.render() .. note:: In order to play interactively with web side application objects, we have to cheat a bit to have request object that will looks like HTTP request object, by calling :meth:`use_web_compatible_requests()` on the connection. This creates an automatic entity form. The ``.render()`` call yields an html (unicode) string. The html output is shown below (with internal fieldset omitted). Looking at the html output ~~~~~~~~~~~~~~~~~~~~~~~~~~ The form enveloppe '''''''''''''''''' .. sourcecode:: html
main informations
validating...
...
The main fieldset encloses a set of hidden fields containing various metadata, that will be used by the `edit controller` to process it back correctly. The `freezeFormButtons(...)` javascript callback defined on the ``onlick`` event of the form element prevents accidental multiple clicks in a row. The ``action`` of the form is mapped to the ``validateform`` controller (situated in :mod:`cubicweb.web.views.basecontrollers`). A full explanation of the validation loop is given in :ref:`validation_process`. .. _attributes_section: The attributes section '''''''''''''''''''''' We can have a look at some of the inner nodes of the form. Some fields are omitted as they are redundant for our purposes. .. sourcecode:: html
... (description field omitted) ... ... (type field omitted) ...
importance
version in which this ticket will be / has been done
Note that the whole form layout has been computed by the form renderer. It is the renderer which produces the table structure. Otherwise, the fields html structure is emitted by their associated widget. While it is called the `attributes` section of the form, it actually contains attributes and *mandatory relations*. For each field, we observe: * a dedicated row with a specific class, such as ``title_subject_row`` (responsability of the form renderer) * an html widget (input, select, ...) with: * an id built from the ``rtype-role:eid`` pattern * a name built from the same pattern * possible values or preselected options The relations section ''''''''''''''''''''' .. sourcecode:: html
This ticket :
  
The optional relations are grouped into a drop-down combo box. Selection of an item triggers a javascript function which will: * show already related entities in the div of id `relatedentities` using a two-colown layout, with an action to allow deletion of individual relations (there are none in this example) * provide a relation selector in the div of id `relationSelector_EID` to allow the user to set up relations and trigger dynamic action on the last div * fill the div of id `unrelatedDivs_EID` with a dynamically computed selection widget allowing direct selection of an unrelated (but relatable) entity or a switch towards the `search mode` of |cubicweb| which allows full browsing and selection of an entity using a dedicated action situated in the left column boxes. The buttons zone '''''''''''''''' Finally comes the buttons zone. .. sourcecode:: html
The most notable artifacts here are the ``postForm(...)`` calls defined on click events on these buttons. This function basically submits the form. .. _validation_process: The form validation process --------------------------- Validation loop ~~~~~~~~~~~~~~~ On form submission, the form.action is invoked. Basically, the ``validateform`` controller is called and its output lands in the specified ``target``, an invisible `` The ``window.parent`` part ensures the javascript function is called on the right context (that is: the form element). We will describe its parameters: * first comes the form id (`entityForm`) * then two optional callbacks for the success and failure case * an array containing: * a boolean which indicates status (success or failure), and then, on error: * an array structured as ``[eid, {'rtype-role': 'error msg'}, ...]`` * on success: * a url (string) representing the next thing to jump to Given the array structure described above, it is quite simple to manipulate the DOM to show the errors at appropriate places. Explanation ~~~~~~~~~~~ This mecanism may seem a bit overcomplicated but we have to deal with two realities: * in the (strict) XHTML world, there are no iframes (hence the dynamic inclusion, tolerated by Firefox) * no (or not all) browser(s) support file input field handling through ajax.