Creating a custom form field type
From Joomla! Documentation
JForm, a feature introduced in Joomla 1.6, lets you easily create HTML forms (<form>
). Forms created using JForm consist of form fields, implemented as JFormFields. There is a JFormField for each different field type you can find in a form, such as a text field type and a date field type. JForm supports a large selection of standard field types. For a full list, see Standard form field types.
Joomla 1.6 makes it possible to override and/or extend these field types. Here is how to do that.
Step 1: Location of files[edit]
- The default form fields are located in "joomla/libraries/joomla/form/fields/"
- The overridden fields are usually located in "administrator/components/<name of your component>/models/fields", you can specify this or other path from your code:
JForm::addFieldPath(JPATH_COMPONENT . DS . 'models' . DS . 'fields');
- The XML files with form fields are usually located in "administrator/components/<name of your component>/models/forms". Use something like the following snippet to specify a path to your forms:
JForm::addFormPath(JPATH_COMPONENT . DS . 'models' . DS . 'forms');
Step 2: Setting up base[edit]
The first file to create is your base class. The base class is your starting point for overriding JFormField.
Create a new file called myform.php and place it in the folder administrator/components/<name of your component>/models/fields. Add the following code to the file:
<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');
abstract class JFormFieldMyForm extends JFormField {
protected $type = 'MyForm';
}
Important lines:
- abstract class JFormFieldMyForm extends JFormField
The name of the file is myform.php this means the name of the class must be the same
- protected $type = 'MyForm';
The $type must also have the same name as your class
Step 3: Creating a field override[edit]
With the base class in place we can now create our field overrides.
Create a new file called mylist.php and place it in the folder administrator/components/<name of your component>/models/fields. Add the following code to the file:
<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');
jimport('joomla.form.helper');
JFormHelper::loadFieldClass('MyForm');
class JFormFieldMyText extends JFormFieldMyForm {
protected $type = 'MyText';
public function getInput() {
$field = JFormHelper::loadFieldType('Text');
// Workaround
$field->setForm($this->form);
$field->setup($this->element, $this->value, $this->group);
return $field->getInput();
}
}
Important lines:
- JFormHelper::loadFieldClass('MyForm');
Here we load our base class
- class JFormFieldMyText extends JFormFieldMyForm {
Here we create our override called MyText and make it extend MyForm, our base class. The class name must always be the same as the filename
- protected $type = 'MyText';
Same as the base class the field class also needs a $type set, this is the same name as your class name
- public function getInput() {
A field override class must always have the public function getInput()
Notice: This example contains a workaround until bug 21644 (http://joomlacode.org/gf/project/joomla/tracker/?action=TrackerItemEdit&tracker_item_id=21644) has been fixed.
Grouping custom field types[edit]
Custom field types can be grouped by using an underscore in the field name. A field class with a name for example like "JFormFieldMy_randomField" must be stored in "administrator/components/<name of your component>/models/fields/my/randomField.php". We can prefix our form field names with some group name, then we put an underscore and then a name of a field.
Step 4: Using the override field[edit]
To use the override field MyText, we need to update the XML file that contains the form fields. Open your XML file located in administrator/components/<name of your component>/models/forms and find a field that is of the type text. This example is from article.xml:
<field name="title" type="text" label="JGLOBAL_TITLE"
description="JFIELD_TITLE_DESC" class="inputbox" size="30"
required="true" />
We change this field to look like this:
<field name="title" type="MyText" label="JGLOBAL_TITLE"
description="JFIELD_TITLE_DESC" class="inputbox" size="30"
required="true" />
Notice how type="text" changed to type="MyText". The MyText here refers to the class made in step 3. The type name is cAsE-sEnSiTiVe.
With these changes in place, your override is done and ready to use.
Overriding getLabel()[edit]
There are 2 ways of overriding the getLabel() method:
- Wrap it in your own tags
- Modify it completely
Wrapping the label[edit]
To wrap a form label you can add the following function to your myform.php file:
public function getLabel() {
return '<span style="text-decoration: underline;">' . parent::getLabel() . '</span>';
}
This code will underline your form labels.
Writing your own label[edit]
To write your own label you can add the following function to your myform.php file:
public function getLabel() {
// Initialize variables.
$label = '';
$replace = '';
// Get the label text from the XML element, defaulting to the element name.
$text = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name'];
// Build the class for the label.
$class = !empty($this->description) ? 'hasTip' : '';
$class = $this->required == true ? $class.' required' : $class;
// Add replace checkbox
$replace = '<input type="checkbox" name="update['.$this->name.']" value="1" />';
// Add the opening label tag and main attributes attributes.
$label .= '<label id="'.$this->id.'-lbl" for="'.$this->id.'" class="'.$class.'"';
// If a description is specified, use it to build a tooltip.
if (!empty($this->description)) {
$label .= ' title="'.htmlspecialchars(trim(JText::_($text), ':').'::' .
JText::_($this->description), ENT_COMPAT, 'UTF-8').'"';
}
// Add the label text and closing tag.
$label .= '>'.$replace.JText::_($text).'</label>';
return $label;
}
This example will add a checkbox before the label.