-
Notifications
You must be signed in to change notification settings - Fork 0
XML Forms
Traditionally, creating view templates involves a .php file where PHP and HTML code are intermixed to create the appropriate representation of the data to be served to a web browser. While this gives maximum flexibility to the developer it is also a drag, requiring you to write a lot of repetitive code, especially for the more formulaic back-end views.
Since Joomla! 1.6 there is a solution to this problem, at least for edit views: JForm. With it it's possible to create an XML file which defines the controls of the form and have JForm render it as HTML.
Pros:
-
The view templates are easier to read
-
The HTML generation is abstracted, making it easier to upgrade to newer versions of Joomla! using a different HTML structure
Cons:
-
You need to change your Controllers, Models and Views to cater for and display the forms
-
They only apply to edit views
FOF takes this concept further with the Form package. Not only can you create edit views, but you can also create browse (records listing) and read (single record display) views out of XML forms. Moreover, the forms are handled automatically by the FOF base MVC classes without requiring you to write any additional code. If you want you can always combine a traditional .php view template or a Blade view template with a form file for maximum customisation of your view.
As implied above, there are three types of XML forms available in FOF: Browse, Read and Edit. Each one follows slightly different conventions and is used in different tasks of each MVC view.
There a few things you should know before we go into more details.
-
All form files are placed in your view's tmpl directory, e.g.
components/com_example/View/Items/tmpl
. -
All form files' names begin with
form.
and end with.xml
. This is required for Joomla! to distinguish them from view metadata XML files. The middle part of their name follows the same convention as the regular view template files, i.e.default
for browse tasks,form
for edit tasks anditem
for read tasks.
For example, the browse form for com_example
's Items
view is located in components/com_example/View/Items/tmpl/form.default.xml
whereas the form for editing a single item is located in components/com_example/View/Item/tmpl/form.form.xml
.
Browse forms are used to create a records list view. They are typically used in the back-end to allow the user to view and manipulate a list of records. A typical browse form looks like this:
<?xml version="1.0" encoding="utf-8"?>
<form
type="browse"
lessfiles="media://com_example/css/backend.less||media://com_example/css/backend.css"
show_header="1"
show_filters="1"
show_pagination="1"
norows_placeholder="COM_EXAMPLE_COMMON_NORECORDS"
relation_depth="2"
>
<headerset>
<header name="ordering" type="Ordering" sortable="true" tdwidth="1%" />
<header name="example_item_id" type="RowSelect" tdwidth="20" />
<header name="title" type="Searchable" sortable="true"
buttons="yes" buttonclass="btn"
/>
<header name="due" type="Field" sortable="true" tdwidth="12%" />
<header name="enabled" type="Published" sortable="true" tdwidth="8%" />
</headerset>
<fieldset name="items">
<field name="ordering" type="Ordering" labelclass="order"/>
<field name="example_item_id" type="SelectRow"/>
<field name="title" type="Text"
show_link="true"
url="index.php?option=com_example&view=Item&id=[ITEM:ID]"
empty_replacement="(no title)"
/>
<field name="due" type="DueDate" />
<field name="enabled" type="Published"/>
</fieldset>
</form>
You MUST have exactly one <headerset>
and one <fieldset>
tag. The name attribute of the <fieldset>
MUST always be items
. Extra tags and/or <fieldset>
tags with different name attributes (or no name attributes) will be ignored.
The enclosing <form>
tag MUST have the following mandatory attributes:
type
It must be always set to browse for FOF to recognise this as a Browse form
The enclosing
tag MAY have one or more of the following attributes:lessfiles
FOF allows you to include LESS files to customise the styling of your components. You can give a comma separated list of LESS files' identifiers to be loaded by FOF. For example media://com_example/less/backend.less
Compiled LESS files are cached in the media/lib_fof/compiled directory for efficiency reasons, using a mangled filename to prevent naming clashes. They are not written in your site's cache
or adminstrator/cache
directory as these directories are not supposed to be web-accessible, whereas the compiled CSS files, by definition, need to be web-accessible.
Since LESS files require a lot of memory and time to compile you can also provide an alternative pre-compiled CSS file, separated from your LESS file with two bars. For example: media://com_example/less/backend.less||media://com_example/css/backend.css
cssfiles
This works in the same manner as the lessfiles directive, but you are only supposed to specify standard CSS files. The CSS files are defined using media identifiers, too. For example: media://com_example/css/backend.css
Please note that media file overrides rules are in effect for these CSS files.
jsfiles
Works the same way as cssfiles, but it's used to load Javascript files. The Javascript files are defined using media identifiers, too. For example: media://com_example/js/backend.js
Please note that media file overrides rules are in effect for these Javascript files.
show_header
Should we display the header section of the browse form? This is the place where the field titles are displayed.
show_filters
Should we show the filter section of the browse form? This area is rendered in the sidebar, at the left hand side of the records list, for drop-down lists and below the header for other filters (e.g. text entry boxes).
show_pagination
Should we show the pagination results? That's the links to the first, second, third, …, last page and the drop-down for the number of items per page. It is displayed below the list of records.
norows_placeholder
A translation key displayed instead of a records list when the current view contains no records, e.g. the table is empty or the filters limit display to zero records.
relation_depth
FOF will process the hasOne and belongsTo relations of your model and make their data available to your form. For example, if you're building a form on the Articles model which has a belongsTo relation called "author" to the Authors model then a form field named author.name
would have access to the name
attribute of the Authors record your Articles record belongs to. The default behaviour is to only process relations one level deep. If the Authors model has a belongsTo relation called "agency" to the Agencies table you won't be able to use a field named author.agency.name
to get access to the author's agency name unless you set relation_depth="2"
or to a higher number. Beware! This feature is handy but it results in a LOT of database queries and intense memory use. Keep in mind that FOF preloads the data for all hasOne and belongsTo relations of all records displayed in the form, even the relations NOT appearing anywhere in your form: the data loading comes. If you want to disable this feature set relation_depth="0"
.
While browse views display a list of records, read forms will display just a single record. These are nowhere near as powerful as hand-coded PHP-based view templates but can be used to get a quick single item output in a snatch when prototyping a component or when your data is really simple. A typical read form looks like this:
<?xml version="1.0" encoding="utf-8"?>
<form
lessfiles="media://com_example/css/frontend.less||media://com_example/css/frontend.css"
type="read"
>
<fieldset name="a_single_item" class="example-item-container form-horizontal">
<field name="title" type="Text"
label=""
class="example-title-field"
size="50"
/>
<field name="due" type="DueDate"
label="COM_EXAMPLE_ITEMS_FIELD_DUE"
labelclass="example-field"
size="20"
default="NOW"
/>
<field name="description" type="Editor"
label=""
/>
</fieldset>
</form>
You MUST have at least one <fieldset>
tag. The name attribute of the <fieldset>
is indifferent.
The enclosing <form>
tag MUST have the following attributes:
type
It must be always set to read for FOF to recognise this as a Read form
The enclosing <form>
tag MAY have one or more of the following attributes:
lessfiles
FOF allows you to include LESS files to customise the styling of your components. You can give a comma separated list of LESS files' identifiers to be loaded by FOF. For example media://com_example/less/backend.less
Compiled LESS files are cached in the media/lib_fof/compiled directory for efficiency reasons, using a mangled filename to prevent naming clashes. They are not written in your site's cache
or adminstrator/cache
directory as these directories are not supposed to be web-accessible, whereas the compiled CSS files, by definition, need to be web-accessible.
Since LESS files require a lot of memory and time to compile you can also provide an alternative pre-compiled CSS file, separated from your LESS file with two bars. For example: media://com_example/less/backend.less||media://com_example/css/backend.css
cssfiles
This works in the same manner as the lessfiles directive, but you are only supposed to specify standard CSS files. The CSS files are defined using media identifiers, too. For example: media://com_example/css/backend.css
Please note that media file overrides rules are in effect for these CSS files.
jsfiles
Works the same way as cssfiles, but it's used to load Javascript files. The Javascript files are defined using media identifiers, too. For example: media://com_example/js/backend.js
Please note that media file overrides rules are in effect for these Javascript files.
Edit forms are used to edit a single record. They are typically used in the back-end. If you want to use an Edit form in the front-end you will need to specialise your Toolbar class to render a front-end toolbar in the edit task of this specific view, otherwise the form will not be able to be submitted (unless you do other tricks, outside the scope of this documentation).
An edit form looks like this:
<?xml version="1.0" encoding="utf-8"?>
<form
lessfiles="media://com_example/css/backend.less||media://com_example/css/backend.css"
validate="true"
serverside_validate="true"
>
<fieldset name="basic_configuration"
label="COM_EXAMPLE_ITEMS_GROUP_BASIC"
description="COM_EXAMPLE_ITEMS_GROUP_BASIC_DESC"
class="span6"
>
<field name="title" type="Text"
class="inputbox"
label="COM_EXAMPLE_ITEMS_FIELD_TITLE"
labelclass="example-label example-label-main"
required="true"
size="50"
/>
<field name="due" type="Calendar"
class="inputbox"
label="COM_EXAMPLE_ITEMS_FIELD_DUE"
labelclass="example-label"
required="true"
size="20"
default="NOW"
/>
<field name="enabled" type="List" label="JSTATUS"
labelclass="example-label"
description="JFIELD_PUBLISHED_DESC" class="inputbox"
filter="intval" size="1" default="1"
>
<option value="1">JPUBLISHED</option>
<option value="0">JUNPUBLISHED</option>
</field>
</fieldset>
<fieldset name="description_group"
label="COM_EXAMPLE_ITEMS_GROUP_DESCRIPTION"
description="COM_EXAMPLE_ITEMS_GROUP_DESCRIPTION_DESC"
class="span6"
>
<field name="description" type="Editor"
label=""
class="inputbox"
required="false"
filter="JComponentHelper::filterText" buttons="true"
/>
</fieldset>
</form>
The enclosing <form>
of an edit view does not have any mandatory attributes.
WARNING If you put a type
attribute you may confuse the FOF form renderer, making it believe it has to render a browse or read form. In this case you will get inexplicable warnings about trying to access the properties of a non-object and finally a fatal error. If this ever happens to you take a look at your <form>
tag and remove the type
attribute. This situation happens a lot when you're copying a browse or read form to save you some time when building the edit form. We've all been there.
The enclosing <form>
tag MAY have one or more of the following attributes:
lessfiles
FOF allows you to include LESS files to customise the styling of your components. You can give a comma separated list of LESS files' identifiers to be loaded by FOF. For example media://com_example/less/backend.less
Compiled LESS files are cached in the media/lib_fof/compiled directory for efficiency reasons, using a mangled filename to prevent naming clashes. They are not written in your site's cache
or adminstrator/cache
directory as these directories are not supposed to be web-accessible, whereas the compiled CSS files, by definition, need to be web-accessible.
Since LESS files require a lot of memory and time to compile you can also provide an alternative pre-compiled CSS file, separated from your LESS file with two bars. For example: media://com_example/less/backend.less||media://com_example/css/backend.css
cssfiles
This works in the same manner as the lessfiles directive, but you are only supposed to specify standard CSS files. The CSS files are defined using media identifiers, too. For example: media://com_example/css/backend.css
Please note that media file overrides rules are in effect for these CSS files.
jsfiles
Works the same way as cssfiles, but it's used to load Javascript files. The Javascript files are defined using media identifiers, too. For example: media://com_example/js/backend.js
Please note that media file overrides rules are in effect for these Javascript files.
validation
Set it to true to have Joomla! load its unobtrusive Javascript validation script.
serverside_validate
Set it to true to have FOF run server-side validation of fields marked as required
. These server-side validations are a bit generic. We recommend you to implement your own server-side validation in your model's check()
method.
Do note that even when serverside_validate
is not set FOF will still call the model's check()
method. The serverside_validate
attribute only affects form field validation checks, not the model's internal data validation. Finally, keep in mind that form field validation is part of the DataModel's check()
method. If you override it in your Model without calling parent::check()
the serverside_validate
attribute will have no effect at all!
customTask
Force the default task when submitting the form. By default there is an empty default task. The toolbar buttons are supposed to set it to a non-empty value. However, if you are using an XML form without a toolbar button –or if the Javascript fails to run– the submitted task is empty and FOF will try to guess if it's an edit or a save task. By setting this attribute you can override this behaviour, forcing a specific or custom default task, e.g. savenew
or foobar
, to be sent instead. This is mostly useful in front-end forms which use a simple HTML submit button instead of a Jvascript-powered toolbar button.
chosen
By default FOF uses Chosen, just like Joomla!, to beautify drop-down lists and multiple selection boxes. Unlike Joomla! which defaults to using Chosen only on fields with the advancedSelect
CSS class, FOF applies Chosen to all <select>
elements. You can change this behaviour by setting the chosen
attribute in the <form>
tag. There are two forms of the attribute you can use:
-
chosen="false"
will instruct FOF to not load Chosen. Be aware that other extensions may load it anyway. -
chosen="selector"
whereselector
is a CSS selector such asselect
(all<select>
elements),.advancedSelect
(all elements with the CSS classadvancedSelect
),#something
(the element with the IDsomething
) etc. To replicate Joomla!'s default behaviour set thechosen=".advancedSelect"
attribute.
The automatically rendered forms can be a timesaver but they look terrible. This is expected since we're talking about automated output coming from a generic solution.
For starters, the <fieldset>
s of Edit and Read forms, as well as the fields themselves, can be assigned CSS classes and IDs which can help you provide a custom style. Moreover, you can mix XML forms and PHP-based view templates to further customise the display of your forms. If this doesn't sound enough for your project you can always use hand-coded PHP-based view templates, much like how you did since Joomla! 1.5.0 or the more powerful Blade templates. It's up to you to decide which method is best for your project.
This feature simply emits Bootstrap 2.x compatible HTML markup, therefore only works with Bootstrap-powered templates. This means that you will need to be using a Bootstrap-powered template on your site.
If you have a long form you may want to provide tabs to let the user access different sections of the form. In order to do that, you first have to set the tabbed attribute of your form to true, yes, 1 or on. For example:
<?xml version="1.0" encoding="utf-8"?>
<form tabbed="1">
Each fieldset which will be part of the tab set must include tab-pane in its class attribute. Moreover, it MUST have non-empty label and name attributes. For example:
<fieldset name="basic_configuration"
label="COM_FOOBAR_ITEMS_GROUP_BASIC"
class="tab-pane active another-class"
>
Please note that exactly one of your <fieldset>
s MUST have active
added to its class attribute. This will be the tab which will be open by default. If you forget to set an active tab the tab pane will render with no tab active by default which is confusing for your users.
If you add a non tabbed <fieldset>
inside a tabbed form the <fieldset>
will be render at the bottom of the form and will appear on all tabs.
If you want to assign more than one <fieldset>
on the same tab you have to use the following attributes on the <fieldset>
:
innertab
The name of the tabbed fieldset where this fieldset will be assign.
The tabbed <fieldset>
which have assigned inner <fieldset>
s can use the following attributes:
class
One or more CSS classes to be applied to the generated <div>
element of the tab .
innerclass
One or more CSS classes to be applied to the generated <div>
element of the fieldset .
For example, to create a tab with 2 <fieldset>
s :
<fieldset name="basic_configuration"
label="COM_FOOBAR_ITEMS_GROUP_BASIC"
class="tab-pane active another-class"
innerclass="span6"
>
<fieldset name="other_configuration"
label="COM_FOOBAR_ITEMS_GROUP_OTHER"
class="span6"
innertab="basic_configuration"
>
Each fieldset of a Read and Edit form can have the following optional attributes:
class
One or more CSS classes to be applied to the generated <div>
element.
name
The value of this attribute is applied to the id
attribute of the generated <div>
element.
label
The value of this attribute is rendered as a level 3 heading (<h3>
) element at the beginning of the generated <div>
element's content.
You can use Bootstrap's classes to create visually interesting interfaces. For example, using class="span6 pull-left"
will create a half-page-wide left floating sidebar out of your field set.
It goes without saying that if your template uses different CSS class names for formatting the content (e.g. Bootstrap 3, Zurb Framework etc) you can use them instead. We've found that mixing Bootstrap 2.3 and Bootstrap 3 CSS class names is possible and allows your component to render nicely on the majority of Joomla! templates since they're generally using either of these two Bootstrap versions.
Each fieldset of a Read and Edit form can optionally include an external view template (PHP or Blade) or even an entirely different View of the same or a different model in a fieldset. The external view will appear before the fieldset's fields. If you don't want any fields to appear just create a fieldset without any fields. The following attributes are used to specify an external view.
source
(mandatory) The URI of the view template you want to load. For example admin:com_example/Items/summary
source_component
(optional) The component providing the View object class to render the view template. By default it's the component the XML form lives in. Otherwise specify the component name, e.g. com_example
.
source_view
(optional) The name of the view for the View object class which renders the view template. By default FOF will use a new FOF30\View\View
object instance with the name FAKE_FORM_VIEW
. Otherwise specify the view name, e.g. 'Items'.
The view name is fed through the view()
method of the Factory object of the container for the component specified in source_component
. This means that if the component uses a magic factory you don't even need to have a concrete View class.
source_view_type
(optional) The view type (e.g. raw
, html
, form
, json
, csv
, ...) for the View object class which renders the view template. By default FOF will use html
. The view type is fed through the view()
method of the Factory object of the container for the component specified in source_component
.
FOF will create a View object based on the information above. It will then call its populateFromModel
method, passing it the Model object used to render the XML form. You can override that method on your View class if you need to set up view properties based on the data contained in the model
FOF also passes a few variables to the view template:
- model (type
FOF30\Model\DataModel
) The model of the form being rendered - form (type
FOF30\Form\Form
) The form currently being rendered - fieldset (type
SimpleXMLElement
) The fieldset currently being rendered - formType (type
string
) The type of the form being rendered, e.g. "read" or "edit" - innerHtml (type
array
) SeeFOF30\Render\RenderInterface::renderFieldset
for information
FOF (Framework on Framework) and its documentation are Copyright © 2010-2020 Nicholas K. Dionysopoulos / Akeeba Ltd.
FOF is Open Source Software, distributed under the GNU General Public License, version 2 of the license, or (at your option) any later version.
The FOF Wiki content is provided under the GNU Free Documentation License, version 1.3 of the license, or (at your option) any later version.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license can be found on the GNU site.