Creating a custom form field type

From Joomla! Documentation

Revision as of 19:38, 14 August 2010 by Elkuku (talk | contribs) (+syntax highlighting)

A new feature in Joomla 1.6 is called JForm which lets you to easily create forms, one part of JForm is JFormFields. JFormFields takes care of all the different fields you can find in a form. JFormFields supports a large selection of fields, see the Standard form field types for in-depth info.

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.