Actions

Creating a custom form field type

From Joomla! Documentation

Revision as of 07:38, 7 June 2011 by Mvangeest (Talk | contribs)

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.

Contents

Step 1: Location of files

  • 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

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

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

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

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()

There are 2 ways of overriding the getLabel() method:

  1. Wrap it in your own tags
  2. Modify it completely

Wrapping the label

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

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.