Section: Displaying a form in a template
« Initializing a form | ^ jForms: automatic forms | Using a form after a submit » |
− Table of content
To display a form and its data, you could call getAllData
on your form object and assign its returned array to a template. With it, you'll be able to generate your HTML form along with its data. if you want to display input errors, call getErrors
to retrieve them and again display them as you like in your template.
However there are some template plugins in Jelix, to prevent you from doing this long and sometimes boring task. They even do a lot more:
- display each control field as described in your XML form,
- display each control label in
<label>
tag to improve ergonomy and accessibility, - display error messages,
- display help messages,
- generate javascript for client-side checking before posting data,
- valid HTML generated and good support of accessibility,
- ids and classes on elements to ease styling.
Full automatic form display with formfull ¶
For you in a hurry, this template plugin will fully display your form. Its name: formfull
. With it, you won't control how each field, labels and submits are displayed. Still you can customize display of help and error messages (see further).
Here are its arguments, in the order:
- your form object
- a selector specifying the target action
- optional:
- an array containing extra url parameters (other than fields data)
- the name of the builder ('html' or 'htmllight' for instance)
- an array containing options for the builder
Example in your controller :
$form = jForms::get('myform');
$tpl = new jTpl();
$tpl->assign('form', $form);
And in your template :
<h1>My form</h1>
<p>Fill this form :</p>
{formfull $form, 'mymodule~default:save'}
Labels and control fields will be displayed in a table, and submit buttons in a div below.
Note: because of some limitations of the plugin formfull and the template engine, don't use the plugin inside a loop, where the variable passed to the plugin is generated by the loop (typically, in a foreach). In this case, JS and CSS files won't be loaded in the page. A solution is to indicate yourself all CSS and JS files needed by your form.
Customized display ¶
There is not only formfull
. Other plugins exist to control how your form is displayed and precisely in which markup your form controls are wrapped.
The first one form
is the equivalent to formfull
except that its a block plugin. It means that it has an end tag and should contains other plugins and markup controlling the display of your form. Arguments for form
are :
- your form object
- a selector specifying the target action
- optional:
- an array containing extra url parameters (other than fields data)
- the name of the builder ('html' or 'htmllight' for instance)
- an array containing options for the builder
Note: As for the formfull plugin, there are some limitations in the plugin form and the template engine, so don't use the plugin inside a loop, where the variable passed to the plugin is generated by the loop (typically, in a foreach). In this case, JS and CSS files won't be loaded in the page. A solution is to indicate yourself all CSS and JS files needed by your form.
Simple display ¶
formcontrols
plugins loops on form controls (neither submits nor reset). It is a block plugin. Within it, ctrl_label
and ctrl_control
plugins will display respectively label and field of current control. To display submit buttons or reset, use formsubmit
and formreset
.
Example :
{form $form, 'mymodule~default:save'}
<fieldset><legend>Fill : </legend>
{formcontrols}
<p> {ctrl_label} : {ctrl_control} </p>
{/formcontrols}
</fieldset>
<div> {formreset}{formsubmit} </div>
{/form}
Note that form fields will be displayed in the order of their declaration in your XML file. Note also that template here is totally independent of form content and could be reused with more forms.
Advanced display ¶
Some controls need to be displayed differently. To achieve this, you can use ifctrl
inside formcontrols
. Its argument is a list of control names. The code below adds a class on 'name' control only:
{form $form, 'mymodule~default:save'}
<fieldset><legend>Your identtity : </legend>
{formcontrols}
<p {ifctrl 'name'}class="help-needed"{/if}> {ctrl_label} : {ctrl_control} </p>
{/formcontrols}
</fieldset>
Or else, indicate a list of control names to formcontrols
plugin. It will loop only on those controls.
{form $form, 'mymodule~default:save'}
<fieldset><legend>Identity : </legend>
{formcontrols array('lastname','firstname','address')}
<p> {ctrl_label} : {ctrl_control} </p>
{/formcontrols}
</fieldset>
<fieldset><legend>Other fields : </legend>
{formcontrols}
<p> {ctrl_label} : {ctrl_control} </p>
{/formcontrols}
</fieldset>
<div> {formsubmit} </div>
{/form}
Above, we display a series of controls in a first fieldset (lastname, firstname and address) and the others in a second fieldset: formcontrols
loops over controls not already displayed.
Note that ctrl_label
and ctrl_control
also function outside of formcontrols
. In that case, you should indicate a control name.
{form $form, 'mymodule~default:save'}
<fieldset><legend>Identity : </legend>
<table>
<tr><td>{ctrl_label 'lastname'}</td><td>{ctrl_control 'lastname'}</td> </tr>
<tr><td>{ctrl_label 'firstname'}</td><td>{ctrl_control 'firstname'}</td></tr>
</table>
</fieldset>
<fieldset><legend>Other fields : </legend>
{formcontrols}
<p> {ctrl_label} : {ctrl_control} </p>
{/formcontrols}
</fieldset>
<div> {formsubmit} </div>
{/form}
Lastname and firstname fields are displayed precisely in a table whereas other fields are displayed with formcontrols
.
Custom attributes ¶
You can add some html attributes on the HTML element generated with ctrl_control
. To do it, add a second parameter to the ctrl_control
tag: it should be an array ('attribute name'=>'attribute value')
. Give ""
as first parameter when ctrl_control
is used inside a formcontrols
loop.
Customizing display of password controls ¶
Beware that if a password control defines a confirm field (<confirm>
tag in XML) you should control either the display of password
field and confirm
field. The confirm control name is a concatenation of password control name + _confirm
.
See example below:
{form $form, 'mymodule~default:save'}
<fieldset><legend>Account creation : </legend>
<table>
<tr><td>{ctrl_label 'login'}</td><td>{ctrl_control 'login'}</td> </tr>
<tr><td>{ctrl_label 'password'}</td><td>{ctrl_control 'password'}</td></tr>
</table>
</fieldset>
<fieldset><legend>Other infos : </legend>
{formcontrols}
<p> {ctrl_label} : {ctrl_control} </p>
{/formcontrols}
</fieldset>
<div> {formsubmit} </div>
{/form}
Confirm field will appear in the second fieldset and not near password field in the example above. To do so, just display 'password_confirm' in a row below 'password' :
<table>
<tr><td>{ctrl_label 'login'}</td><td>{ctrl_control 'login'}</td> </tr>
<tr><td>{ctrl_label 'password'}</td><td>{ctrl_control 'password'}</td></tr> <tr><td>{ctrl_label 'password_confirm'}</td><td>{ctrl_control 'password_confirm'}</td></tr>
</table>
On the contrary, you should not take care of confirm field in formcontrols
loop.
Customizing display of submit buttons ¶
As you may recall, formsubmit
template plugin displays a submit button declared in your form. But if one declares more than one submit button, formsubmit
will display only the first one. In that case, use formsubmits
(note the ending s). This block template loops over submit buttons :
<ul>
{formsubmits}
<li>{formsubmit}</li>
{/formsubmits}
</ul>
Another way is to use formsubmit
multiple times indicating each submit name :
<div> {formsubmit 'preview'} {formsubmit 'save'} </div>
- *Beware :
{formsubmits}
loops over submit controls, not submit items**! It is not possible to loop over submit items (see ticket #429)
Adding javascript code ¶
You can add behaviors to any controls with javascript, with your prefered js library (jForms uses jQuery).
All generated fields have an id. Ids are composed names: "jforms_module_formname_controlref". For example, for a control with the ref "address", declared in the form "identity" provided the "users" module, the id of the generated field is: "jforms_users_identity_address".
The form element is also generated with an id, composed with the name of the module and the name of the jforms form: "jforms_module_formname". In our example, the id is "jforms_users_identity".
Knowing that, you can retrieve all fields and the form element with the document.getElementById()
function.
To add additionnal check or to run anything you want during the submit event, you should not to use an event listener, but you should add a "submit handler" on the javascript jforms object. A submit handler is a function, accepting a DOM event as parameter, and returning true if the form can be submitted, else false. You add a submit handler with the function addSubmitHandler
on the jforms object.
Here is an example to add a confirmation message:
jQuery(document).ready(function(){
jFormsJQ.getForm("the_id_of_formelement").addSubmitHandler(function(ev){
return window.confirm("Do you really want to submit this data?");
});
});
By default, the handler is executed after the check on data. If you want to add the handler before the check, indicate true as second parameter to addSubmitHandler
.
All handlers (and the data check) are executed, even if one handler or the data checker return false. If you want to stop the execution of handlers following your's, just throw an exception.
Generator choice ¶
jForms template plugins relies on other plugins. Those are jForms plugins and generate effectively a form content (label and fields markup). These are called generators. Jelix have two of them inside : htm
and htmllight
. See documentation to create your own if you need to display custom markup. If you need a generator supporting a javascript library as extjs, or an ajax form, or a XUL form...
Jelix default generator is html
. You can change this in your configuration file. Use defaultJformsBuild variable and assign it your generator of choice :
[tplplugins]
defaultJformsBuilder = myformbuilder
To achieve a fine-grained control, you can even choose a generator in {form}
ou {formfull}
(as fourth argument) :
{formfull $form, 'mymodule~default:save', array(), 'htmllight'}
Those plugins support a fifth parameter which is an array of options passed to the generator (errorDecorator and method for 'html' and htmllight').
Note: You can of course create a new generator as inheriting from an existing one. That way, you can customize only some of the output or set an option directly in its constructor. ...
More about generators :