Difference between revisions of "Creating a custom form field type"

From Joomla! Documentation

Line 172: Line 172:
  
 
<noinclude>[[Category:Development]] [[Category:Form fields]] [[Category:Joomla! 2.5]] [[Category:Joomla! 3.1]]</noinclude>
 
<noinclude>[[Category:Development]] [[Category:Form fields]] [[Category:Joomla! 2.5]] [[Category:Joomla! 3.1]]</noinclude>
 +
{{version/tutor|2.5,3.x}}
 +
{{page|needs review}}
 +
 +
[[JForm]], a feature introduced in Joomla 2.5, lets you easily create HTML forms (<code><form></code>). Forms created using JForm consist of [[Form field|form fields]], implemented as [[JFormField|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 2.5 makes it possible to extend standard field types or define your own. For example, if your component manages phone book entries, you might want to define a form field type that outputs a select list of cities. There are several advantages to defining a custom form field type:
 +
 +
* You will be able to mix standard field types with your custom field type in a JForm-based form.
 +
* You will eventually have a reusable code package that can be used easily throughout your code.
 +
* Extensions that collaborate with your extension will be able to create form fields without meddling with your database tables and other internals.
 +
 +
== Form field type class requirements ==
 +
 +
A form field type is defined in a [[wikipedia:Class (computer programming)|class]] that must be a (not necessarily direct) subclass of JFormField. To work correctly, the class must define at least two methods:
 +
 +
* <code>public function getLabel()</code>
 +
*: This function will be called to create the label that belongs to your field and must return a HTML string containing it. Since JFormField defines a ready-to-use <code>getLabel()</code> implementation, custom form field types usually do not define their own <code>getLabel()</code>. If you leave it out, the inherited method of creating labels will be used. It is recommended to leave out the <code>getLabel()</code> method for consistency and speed unless you actually want to modify the label's HTML.
 +
* <code>public function getInput()</code>
 +
*: This function will be called to create the field itself and must return a HTML string containing it. This is also where most of the processing usually happens. In our phone book City field example, this function will have to retrieve a list of available cities and return a HTML <code><select></code> with the cities inserted as <code><option></code>s.
 +
 +
Inside your code, you will have to process the attributes set by the field's user in the XML form definition. Some of those attributes are accessible via protected member variables of JFormField. For example, the <code>name</code> attribute is available in your code as <code>$this->name</code>. Similarly, <code>label</code>, <code>description</code>, <code>default</code>, <code>multiple</code> and <code>class</code> are also available as properties of <code>$this</code>. Other parameters you might have defined can be accessed through the <code>$this->element</code> array: the attribute <code>size</code> will be in <code>$this->element['size']</code>.
 +
 +
== Which class to subclass? ==
 +
 +
For a form field type to be usable in JForm, it needs to be a subclass of JFormField. However, it does not have to be a direct child of that class: you can also subclass an existing (standard or custom) form field type and thereby inherit useful code.
 +
 +
'''If your form field type is quite similar to an existing type,''' you should subclass that type. Especially if your form field type is a '''list''', please subclass [[JFormFieldList]]. You only have to override <code>getOptions()</code> method to return the options to be shown; the <code>getInput()</code> method will convert those options to HTML.
 +
 +
To subclass an existing type, for example JFormFieldList, load it by adding the following to after <code>jimport('joomla.form.formfield');</code>:
 +
 +
<source lang="php">
 +
jimport('joomla.form.helper');
 +
JFormHelper::loadFieldClass('list');
 +
</source>
 +
 +
'''If your form field type is unlike any existing type,''' subclass JFormField directly.
 +
 +
== Location of files ==
 +
 +
* The standard form field types are located in <code>joomla/libraries/cms/form/fields/</code>. You should not store custom fields there, nor should you have to use this path in your own code, but the standard types are usually good examples.
 +
* The custom field types that belong to your component are usually located in <code>administrator/components/<name of your component>/models/fields</code>. You can specify this or another path in your code:
 +
<source lang="php">JForm::addFieldPath(JPATH_COMPONENT . '/models/fields');</source>
 +
* The XML files that define forms are usually located in <code>administrator/components/<name of your component>/models/forms</code>. Use something like the following snippet to specify a path to your forms:
 +
<source lang="php">JForm::addFormPath(JPATH_COMPONENT . '/models/forms');</source>
 +
 +
== Naming conventions and skeleton ==
 +
 +
In this section, <ComponentName> represents the camel-cased name of your component and <FieldName> represents the camel-cased name of your form field type. The field's class should be placed in <code>administrator/components/<name of your component>/models/fields/<name of your field>.php</code>, and look like this:
 +
 +
<source lang="php"><?php
 +
// Check to ensure this file is included in Joomla!
 +
defined('_JEXEC') or die('Restricted access');
 +
 +
jimport('joomla.form.formfield');
 +
 +
// The class name must always be the same as the filename (in camel case)
 +
class JFormField<FieldName> extends JFormField {
 +
 +
//The field class must know its own type through the variable $type.
 +
protected $type = '<FieldName>';
 +
 +
public function getLabel() {
 +
// code that returns HTML that will be shown as the label
 +
}
 +
 +
public function getInput() {
 +
// code that returns HTML that will be shown as the form field
 +
}
 +
}
 +
</source>
 +
 +
=== Grouping custom field types ===
 +
 +
'''Warning: this information is partially incorrect and needs to be improved.'''
 +
 +
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 <code>administrator/components/<name of your component>/models/fields/my/randomField.php</code>. We can prefix our form field names with some group name, then we put an underscore and then a name of a field.
 +
 +
== An example custom field type ==
 +
 +
Suppose you're working on your component named ''com_phonebook'' and you want to define a field that contains cities. Create the file <code>administrator/components/com_phonebook/models/fields/city.php</code> and write something similar to the following:
 +
 +
<source lang="php"><?php
 +
// Check to ensure this file is included in Joomla!
 +
defined('_JEXEC') or die('Restricted access');
 +
 +
jimport('joomla.form.formfield');
 +
 +
class JFormFieldCity extends JFormField {
 +
 +
protected $type = 'City';
 +
 +
// getLabel() left out
 +
 +
public function getInput() {
 +
return '<select id="'.$this->id.'" name="'.$this->name.'">'.
 +
      '<option value="1" >New York</option>'.
 +
      '<option value="2" >Chicago</option>'.
 +
      '<option value="3" >San Francisco</option>'.
 +
      '</select>';
 +
}
 +
}
 +
</source>
 +
 +
=== Using the custom field type ===
 +
==== Linked with a form ====
 +
To use the field type City, we need to update the XML file that contains the form fields. Open your XML file located in <code>administrator/components/com_phonebook/models/forms</code> and add the field in the usual way:
 +
 +
<source lang="xml"><field name="title" type="City" label="JGLOBAL_TITLE"
 +
description="JFIELD_TITLE_DESC"
 +
required="true" /></source>
 +
The type name is cAsE-sEnSiTiVe.
 +
 +
 +
In addition, you may need to add the field path to the parent <fieldset>:
 +
 +
<source lang="xml">
 +
<fieldset addfieldpath="/administrator/components/<component name>/models/fields">
 +
</source>
 +
 +
==== Not linked with a form ====
 +
E.g. when you need the field as a dropdown in a component as admin/site filter.
 +
<source lang="php">
 +
//Get custom field
 +
JFormHelper::addFieldPath(JPATH_COMPONENT . '/models/fields');
 +
$cities = JFormHelper::loadFieldType('City', false);
 +
$cityOptions=$cities->getOptions(); // works only if you set your field getOptions on public!!
 +
</source>
 +
 +
== Overriding <code>getLabel()</code> ==
 +
 +
As mentioned in the section [[#Form field type class requirements|Form field type class requirements]], custom form field types usually do not define their own <code>getLabel()</code>. If you do want to create a custom label, you can still make use of the <code>getLabel()</code> that every field type class inherits from JFormField, for example by defining it as follows:
 +
 +
<source lang="php">public function getLabel() {
 +
    return '<span style="text-decoration: underline;">' . parent::getLabel() . '</span>';
 +
} </source>
 +
 +
This code will underline your form labels. (Please note that if your goal is to underline form labels, using [[CSS]] is the preferred way.)
 +
 +
If you want to do something completely different, you can of course also override it completely:
 +
 +
<source lang="php">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;
 +
}</source>
 +
 +
This example will add a checkbox inside the label.
 +
 +
<noinclude>[[Category:Development]] [[Category:Form fields]] [[Category:Joomla! 2.5]] [[Category:Joomla! 3.1]]</noinclude>
 +
 +
=== Adding XML include file functionality ===
 +
 +
XML form definitions are cumbersome, and maintaining a number of similar forms can be problematic if fieldset and field definitions have only minor differences between forms.
 +
 +
You can alleviate a lot of the drudgery by grouping your fieldset or field definitions in additional files and then include those files in your top level form definition.
 +
 +
This will require you to make a slight modification to the /libraries/joomla/form/form.php file, but this is a small price to pay for flexibility gained.
 +
 +
In method <source lang="php">loadFile($file, $reset = true, $xpath = false)</source> (line 867 in Joomla 3.1)
 +
 +
change:
 +
 +
<source lang="php">$xml = simplexml_load_file($file);</source>
 +
 +
to:
 +
 +
<source lang="php">$xml = simplexml_load_file($file, 'SimpleXMLElement', LIBXML_NOENT);</source>
 +
 +
At the top of your master form definition file you would add something like this:
 +
 +
<source lang="xml">
 +
<?xml version="1.0" encoding="utf-8"?>
 +
<!DOCTYPE form [
 +
    <!ENTITY include1 SYSTEM "includefile1.xml">
 +
    ...
 +
  <!ENTITY include4 SYSTEM "includefile4.xml">
 +
]>
 +
</source>
 +
 +
Then, insert the ENTITY identifier in your master definition file in the following way:
 +
 +
<source lang="xml">%include1;</source>
 +
 +
So by way of example if your master xml form definition looks like this:
 +
 +
<source lang="xml">
 +
<?xml version="1.0" encoding="utf-8"?>
 +
<!DOCTYPE form [
 +
    <!ENTITY include1 SYSTEM "includefile1.xml">
 +
    <!ENTITY include2 SYSTEM "includefile2.xml">
 +
]>
 +
<form>
 +
    <fieldset>
 +
      <field name="id" type="hidden" filter="integer"/>
 +
      &include1;
 +
    </fieldset>
 +
    &include2;
 +
</form>
 +
</source>
 +
 +
and includefile1.xml looks like this:
 +
 +
<source lang="xml">
 +
<field name="email" type="email" label="COM_USERS_EMAIL_LABEL" required="true"/>
 +
</source>
 +
 +
and includefile2.xml looks like this:
 +
 +
<source lang="xml">
 +
<fieldset name="more">
 +
    <field name="first_name" type="text" label="COM_USERS_NAME_LABEL" required="true"/>
 +
</fieldset>
 +
</source>
 +
 +
Then the loaded file used by Joomla in evaluating your form will look like this:
 +
 +
<source lang="xml">
 +
<?xml version="1.0" encoding="utf-8"?>
 +
<!DOCTYPE form [
 +
    <!ENTITY include1 SYSTEM "includefile1.xml">
 +
    <!ENTITY include2 SYSTEM "includefile2.xml">
 +
]>
 +
<form>
 +
    <fieldset>
 +
      <field name="id" type="hidden" filter="integer"/>
 +
      <field name="email" type="email" label="COM_USERS_EMAIL_LABEL" required="true"/>
 +
    </fieldset>
 +
    <fieldset name="more">
 +
        <field name="first_name" type="text" label="COM_USERS_NAME_LABEL" required="true"/>
 +
    </fieldset>
 +
</form>
 +
</source>

Revision as of 13:39, 14 July 2014

Copyedit.png
This Article Needs Your Help

This article is tagged because it NEEDS REVIEW. You can help the Joomla! Documentation Wiki by contributing to it.
More pages that need help similar to this one are here. NOTE-If you feel the need is satistified, please remove this notice.


JForm, a feature introduced in Joomla 2.5, 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 2.5 makes it possible to extend standard field types or define your own. For example, if your component manages phone book entries, you might want to define a form field type that outputs a select list of cities. There are several advantages to defining a custom form field type:

  • You will be able to mix standard field types with your custom field type in a JForm-based form.
  • You will eventually have a reusable code package that can be used easily throughout your code.
  • Extensions that collaborate with your extension will be able to create form fields without meddling with your database tables and other internals.

Form field type class requirements[edit]

A form field type is defined in a class that must be a (not necessarily direct) subclass of JFormField. To work correctly, the class must define at least two methods:

  • public function getLabel()
    This function will be called to create the label that belongs to your field and must return a HTML string containing it. Since JFormField defines a ready-to-use getLabel() implementation, custom form field types usually do not define their own getLabel(). If you leave it out, the inherited method of creating labels will be used. It is recommended to leave out the getLabel() method for consistency and speed unless you actually want to modify the label's HTML.
  • public function getInput()
    This function will be called to create the field itself and must return a HTML string containing it. This is also where most of the processing usually happens. In our phone book City field example, this function will have to retrieve a list of available cities and return a HTML <select> with the cities inserted as <option>s.

Inside your code, you will have to process the attributes set by the field's user in the XML form definition. Some of those attributes are accessible via protected member variables of JFormField. For example, the name attribute is available in your code as $this->name. Similarly, label, description, default, multiple and class are also available as properties of $this. Other parameters you might have defined can be accessed through the $this->element array: the attribute size will be in $this->element['size'].

Which class to subclass?[edit]

For a form field type to be usable in JForm, it needs to be a subclass of JFormField. However, it does not have to be a direct child of that class: you can also subclass an existing (standard or custom) form field type and thereby inherit useful code.

If your form field type is quite similar to an existing type, you should subclass that type. Especially if your form field type is a list, please subclass JFormFieldList. You only have to override getOptions() method to return the options to be shown; the getInput() method will convert those options to HTML.

To subclass an existing type, for example JFormFieldList, load it by adding the following to after jimport('joomla.form.formfield');:

jimport('joomla.form.helper');
JFormHelper::loadFieldClass('list');

If your form field type is unlike any existing type, subclass JFormField directly.

Location of files[edit]

  • The standard form field types are located in joomla/libraries/cms/form/fields/. You should not store custom fields there, nor should you have to use this path in your own code, but the standard types are usually good examples.
  • The custom field types that belong to your component are usually located in administrator/components/<name of your component>/models/fields. You can specify this or another path in your code:
JForm::addFieldPath(JPATH_COMPONENT . '/models/fields');
  • The XML files that define forms 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 . '/models/forms');

Naming conventions and skeleton[edit]

In this section, <ComponentName> represents the camel-cased name of your component and <FieldName> represents the camel-cased name of your form field type. The field's class should be placed in administrator/components/<name of your component>/models/fields/<name of your field>.php, and look like this:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

jimport('joomla.form.formfield');

// The class name must always be the same as the filename (in camel case)
class JFormField<FieldName> extends JFormField {

	//The field class must know its own type through the variable $type.
	protected $type = '<FieldName>';

	public function getLabel() {
		// code that returns HTML that will be shown as the label
	}

	public function getInput() {
		// code that returns HTML that will be shown as the form field
	}
}

Grouping custom field types[edit]

Warning: this information is partially incorrect and needs to be improved.

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.

An example custom field type[edit]

Suppose you're working on your component named com_phonebook and you want to define a field that contains cities. Create the file administrator/components/com_phonebook/models/fields/city.php and write something similar to the following:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

jimport('joomla.form.formfield');

class JFormFieldCity extends JFormField {
	
	protected $type = 'City';

	// getLabel() left out

	public function getInput() {
		return '<select id="'.$this->id.'" name="'.$this->name.'">'.
		       '<option value="1" >New York</option>'.
		       '<option value="2" >Chicago</option>'.
		       '<option value="3" >San Francisco</option>'.
		       '</select>';
	}
}

Using the custom field type[edit]

Linked with a form[edit]

To use the field type City, we need to update the XML file that contains the form fields. Open your XML file located in administrator/components/com_phonebook/models/forms and add the field in the usual way:

<field name="title" type="City" label="JGLOBAL_TITLE"
	description="JFIELD_TITLE_DESC"
	required="true" />

The type name is cAsE-sEnSiTiVe.


In addition, you may need to add the field path to the parent <fieldset>:

<fieldset addfieldpath="/administrator/components/<component name>/models/fields">

Not linked with a form[edit]

E.g. when you need the field as a dropdown in a component as admin/site filter.

//Get custom field
JFormHelper::addFieldPath(JPATH_COMPONENT . '/models/fields');
$cities = JFormHelper::loadFieldType('City', false);
$cityOptions=$cities->getOptions(); // works only if you set your field getOptions on public!!

Overriding getLabel()[edit]

As mentioned in the section Form field type class requirements, custom form field types usually do not define their own getLabel(). If you do want to create a custom label, you can still make use of the getLabel() that every field type class inherits from JFormField, for example by defining it as follows:

public function getLabel() {
     return '<span style="text-decoration: underline;">' . parent::getLabel() . '</span>';
}

This code will underline your form labels. (Please note that if your goal is to underline form labels, using CSS is the preferred way.)

If you want to do something completely different, you can of course also override it completely:

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 inside the label.

Copyedit.png
This Article Needs Your Help

This article is tagged because it NEEDS REVIEW. You can help the Joomla! Documentation Wiki by contributing to it.
More pages that need help similar to this one are here. NOTE-If you feel the need is satistified, please remove this notice.


JForm, a feature introduced in Joomla 2.5, 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 2.5 makes it possible to extend standard field types or define your own. For example, if your component manages phone book entries, you might want to define a form field type that outputs a select list of cities. There are several advantages to defining a custom form field type:

  • You will be able to mix standard field types with your custom field type in a JForm-based form.
  • You will eventually have a reusable code package that can be used easily throughout your code.
  • Extensions that collaborate with your extension will be able to create form fields without meddling with your database tables and other internals.

Form field type class requirements[edit]

A form field type is defined in a class that must be a (not necessarily direct) subclass of JFormField. To work correctly, the class must define at least two methods:

  • public function getLabel()
    This function will be called to create the label that belongs to your field and must return a HTML string containing it. Since JFormField defines a ready-to-use getLabel() implementation, custom form field types usually do not define their own getLabel(). If you leave it out, the inherited method of creating labels will be used. It is recommended to leave out the getLabel() method for consistency and speed unless you actually want to modify the label's HTML.
  • public function getInput()
    This function will be called to create the field itself and must return a HTML string containing it. This is also where most of the processing usually happens. In our phone book City field example, this function will have to retrieve a list of available cities and return a HTML <select> with the cities inserted as <option>s.

Inside your code, you will have to process the attributes set by the field's user in the XML form definition. Some of those attributes are accessible via protected member variables of JFormField. For example, the name attribute is available in your code as $this->name. Similarly, label, description, default, multiple and class are also available as properties of $this. Other parameters you might have defined can be accessed through the $this->element array: the attribute size will be in $this->element['size'].

Which class to subclass?[edit]

For a form field type to be usable in JForm, it needs to be a subclass of JFormField. However, it does not have to be a direct child of that class: you can also subclass an existing (standard or custom) form field type and thereby inherit useful code.

If your form field type is quite similar to an existing type, you should subclass that type. Especially if your form field type is a list, please subclass JFormFieldList. You only have to override getOptions() method to return the options to be shown; the getInput() method will convert those options to HTML.

To subclass an existing type, for example JFormFieldList, load it by adding the following to after jimport('joomla.form.formfield');:

jimport('joomla.form.helper');
JFormHelper::loadFieldClass('list');

If your form field type is unlike any existing type, subclass JFormField directly.

Location of files[edit]

  • The standard form field types are located in joomla/libraries/cms/form/fields/. You should not store custom fields there, nor should you have to use this path in your own code, but the standard types are usually good examples.
  • The custom field types that belong to your component are usually located in administrator/components/<name of your component>/models/fields. You can specify this or another path in your code:
JForm::addFieldPath(JPATH_COMPONENT . '/models/fields');
  • The XML files that define forms 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 . '/models/forms');

Naming conventions and skeleton[edit]

In this section, <ComponentName> represents the camel-cased name of your component and <FieldName> represents the camel-cased name of your form field type. The field's class should be placed in administrator/components/<name of your component>/models/fields/<name of your field>.php, and look like this:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

jimport('joomla.form.formfield');

// The class name must always be the same as the filename (in camel case)
class JFormField<FieldName> extends JFormField {

	//The field class must know its own type through the variable $type.
	protected $type = '<FieldName>';

	public function getLabel() {
		// code that returns HTML that will be shown as the label
	}

	public function getInput() {
		// code that returns HTML that will be shown as the form field
	}
}

Grouping custom field types[edit]

Warning: this information is partially incorrect and needs to be improved.

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.

An example custom field type[edit]

Suppose you're working on your component named com_phonebook and you want to define a field that contains cities. Create the file administrator/components/com_phonebook/models/fields/city.php and write something similar to the following:

<?php
// Check to ensure this file is included in Joomla!
defined('_JEXEC') or die('Restricted access');

jimport('joomla.form.formfield');

class JFormFieldCity extends JFormField {
	
	protected $type = 'City';

	// getLabel() left out

	public function getInput() {
		return '<select id="'.$this->id.'" name="'.$this->name.'">'.
		       '<option value="1" >New York</option>'.
		       '<option value="2" >Chicago</option>'.
		       '<option value="3" >San Francisco</option>'.
		       '</select>';
	}
}

Using the custom field type[edit]

Linked with a form[edit]

To use the field type City, we need to update the XML file that contains the form fields. Open your XML file located in administrator/components/com_phonebook/models/forms and add the field in the usual way:

<field name="title" type="City" label="JGLOBAL_TITLE"
	description="JFIELD_TITLE_DESC"
	required="true" />

The type name is cAsE-sEnSiTiVe.


In addition, you may need to add the field path to the parent <fieldset>:

<fieldset addfieldpath="/administrator/components/<component name>/models/fields">

Not linked with a form[edit]

E.g. when you need the field as a dropdown in a component as admin/site filter.

//Get custom field
JFormHelper::addFieldPath(JPATH_COMPONENT . '/models/fields');
$cities = JFormHelper::loadFieldType('City', false);
$cityOptions=$cities->getOptions(); // works only if you set your field getOptions on public!!

Overriding getLabel()[edit]

As mentioned in the section Form field type class requirements, custom form field types usually do not define their own getLabel(). If you do want to create a custom label, you can still make use of the getLabel() that every field type class inherits from JFormField, for example by defining it as follows:

public function getLabel() {
     return '<span style="text-decoration: underline;">' . parent::getLabel() . '</span>';
}

This code will underline your form labels. (Please note that if your goal is to underline form labels, using CSS is the preferred way.)

If you want to do something completely different, you can of course also override it completely:

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 inside the label.

Adding XML include file functionality[edit]

XML form definitions are cumbersome, and maintaining a number of similar forms can be problematic if fieldset and field definitions have only minor differences between forms.

You can alleviate a lot of the drudgery by grouping your fieldset or field definitions in additional files and then include those files in your top level form definition.

This will require you to make a slight modification to the /libraries/joomla/form/form.php file, but this is a small price to pay for flexibility gained.

In method

loadFile($file, $reset = true, $xpath = false)

(line 867 in Joomla 3.1)

change:

$xml = simplexml_load_file($file);

to:

$xml = simplexml_load_file($file, 'SimpleXMLElement', LIBXML_NOENT);

At the top of your master form definition file you would add something like this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE form [
    <!ENTITY include1 SYSTEM "includefile1.xml">
    ... 
   <!ENTITY include4 SYSTEM "includefile4.xml">
]>

Then, insert the ENTITY identifier in your master definition file in the following way:

%include1;

So by way of example if your master xml form definition looks like this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE form [
    <!ENTITY include1 SYSTEM "includefile1.xml">
    <!ENTITY include2 SYSTEM "includefile2.xml">
]>
<form>
    <fieldset>
      <field name="id" type="hidden" filter="integer"/>
      &include1;
    </fieldset>
    &include2;
</form>

and includefile1.xml looks like this:

<field name="email" type="email" label="COM_USERS_EMAIL_LABEL" required="true"/>

and includefile2.xml looks like this:

<fieldset name="more">
    <field name="first_name" type="text" label="COM_USERS_NAME_LABEL" required="true"/>
</fieldset>

Then the loaded file used by Joomla in evaluating your form will look like this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE form [
    <!ENTITY include1 SYSTEM "includefile1.xml">
    <!ENTITY include2 SYSTEM "includefile2.xml">
]>
<form>
    <fieldset>
      <field name="id" type="hidden" filter="integer"/>
      <field name="email" type="email" label="COM_USERS_EMAIL_LABEL" required="true"/>
    </fieldset>
    <fieldset name="more">
        <field name="first_name" type="text" label="COM_USERS_NAME_LABEL" required="true"/>
    </fieldset>
</form>