Creating a custom form field type

From Joomla! Documentation

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

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:

  1. Wrap it in your own tags
  2. 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.