By Roberto Segura on Monday, 01 April 2013
Category: April

Joomla! 3.1.0 Tag Field

This article describes how to use the new tag field added to Joomla! 3.1.0 and the new tools available for Joomla! developers.

Summary

  1. Introduction
  2. Basic usage
  3. Field mode
    1. Automatic mode
    2. AJAX mode
    3. Nested mode
  4. Allow/deny custom tags
  5. Additional tools
    1. ajax-chosen
    2. Customised tag field
  6. Work in progress

 1. Introduction

As most of you know Joomla! 3.1.0 integrates a new tag system with this key features:

This is a feature that I really missed in Joomla! I've been years wondering why Joomla! had content but not tags.

My small contribution to the system has been the AJAX tag field. Having experienced with another tag systems my field requirements were:

This article describes the new field and all the new libraries and developer tools added into Joomla!

 2. Basic usage

Most extensions are going to use the standard field mode so let's put that information first to save them some time reading this article.

To use the new tag system in any extension you only have to define a new field in your form XML this way:

<field name="tags" type="tag"
label="JTAG" description="JTAG_DESC"
class="inputbox span12 small" multiple="true"
/>

 The key is the type="tag" part. That's all. No worry about dependencies. The system will do the rest for you.

When rendering the form the system will:

  1. Load jQuery.
  2. Load the chosen plugin.
  3. Load the ajax-chosen plugin.
  4. Load our custom JS code to insert custom tags.

 3. Field mode

To be able to cover all the user preferences we decided to take advantage of all the contributed code and let the end user decide how to use the field. In the com_tag options you will find a parameter to adjust the field mode between AJAX or Nested.

 3.1. Automatic mode

If you do not specify the field mode in the tag field definition your field will adjust its behavior to the global com_tags setting. By default the mode is set to AJAX.

 3.2. AJAX mode

To force the field to use the AJAX mode you have to define it this way:

<field name="tags" type="tag" mode="ajax"
label="JTAG" description="JTAG_DESC"
class="inputbox span12 small" multiple="true"
/>

 3.3. Nested mode

To force the field to use the nested mode you have to define it like:

<field name="tags" type="tag" mode="nested"
label="JTAG" description="JTAG_DESC"
class="inputbox span12 small" multiple="true"
/>

 4. Allow/deny custom tags

There are cases when you want the user to select tags but you don't want them to be able to insert new tags. The field includes an extra "custom" attribute to force the field to accept/deny new tags. Note that currently the nested mode does not allow custom tag creation. So this setting only applies to the fields working in AJAX mode.

If you do not specify the "custom" mode the field will allow them by default. The "allow" mode is added just for the case that a setting for the mode is added in the future.

To force the field to allow tags:

<field name="tags" type="tag" custom="allow"
label="JTAG" description="JTAG_DESC"
class="inputbox span12 small" multiple="true"
/>

To force the field to deny tags:

<field name="tags" type="tag" custom="deny"
label="JTAG" description="JTAG_DESC"
class="inputbox span12 small" multiple="true"
/>

You can see examples of custom values allowed in all the core content backend managers. Examples of custom values denied can be found in tag menu items.

 5. Additional tools for developers

For the AJAX search integration with chosen I decided to use the ajax-chosen plugin created by Ryan LeFevre. I thought it would be itself a cool addon for other extensions or core components. The only thing that I had to do was integrate and modify it to allow custom values.

In my crusade to keep all the plugins unmodified and upgradeable I wanted to make available the ajax-chosen as library without tie it to the tag field.

This section will explain how to use the ajax-chosen integration and how to build a customised tag system.

 5.1. ajax-chosen

A new ajaxchosen method has been added to the file:

libraries/cms/html/formbehavior.php

It's definition is:

/**
 * Method to load the AJAX Chosen library
 *
 * If debugging mode is on an uncompressed version of AJAX Chosen is included for easier debugging.
 *
 * @param   JRegistry  $options  Options in a JRegistry object
 * @param   mixed      $debug    Is debugging mode on? [optional]
 *
 * @return  void
 *
 * @since   3.0
 */
public static function ajaxchosen(JRegistry $options, $debug = null)
{
}

The options accepted in the JRegistry $options object are the standard AJAX jQuery options and some specific ajax-chosen options:

I also added a selector option with the selector of the DOM object to initialise as ajax-chosen field automatically when the DOM is ready. For example: #js-myfield

We can take as example the call that the tag field does in the file:

libraries/cms/html/tag.php

// Tags field ajax
$chosenAjaxSettings = new JRegistry(
	array(
		'selector'    => $selector,
		'type'        => 'GET',
		'url'         => JURI::root() . 'index.php?option=com_tags&task=tags.searchAjax',
		'dataType'    => 'json',
		'jsonTermKey' => 'like'
	)
);
JHtml::_('formbehavior.ajaxchosen', $chosenAjaxSettings);

Quite simple! The AJAX results have to be returned as defined in the ajax-chosen documentation.

For standard results the results expected format is:

[{"value": 3, "text": "Ohio"}]

and for grouped results:

[{
    group: true,
    text: "Europe",
    items: [
        { "value": "10", "text": "Stockholm" },
        { "value": "23", "text": "London" }
    ]
},
{
    group: true,
    text: "Asia",
    items: [
        { "value": "36", "text": "Beijing" },
        { "value": "20", "text": "Tokyo" }
    ]
}]

 5.2. Customised tag field

Taking as base our tag field definition it's easy to build our own tag field. For example if we want a tag field to use it on our own extension but don't want to load the data from the core tags tables.

We will take as example the K2 tag system. It uses it's own tag system with the search parameter "q".

The example tag field helper would be:

/**
 * This is just a proxy for the formbehavior.ajaxchosen method
 *
 * @param   string   $selector     DOM id of the tag field
 * @param   boolean  $allowCustom  Flag to allow custom values
 *
 * @return  void
 *
 * @since   3.1
 */
public static function k2tagsfield($selector='#jform_tags', $allowCustom = true)
{
	// Tags field ajax
	$chosenAjaxSettings = new JRegistry(
		array(
			'selector'    => $selector,
			'type'        => 'GET',
			'url'         => JURI::root() . 'index.php?option=com_k2&task=item.tags',
			'dataType'    => 'json',
			'jsonTermKey' => 'q'
		)
	);
	JHtml::_('formbehavior.ajaxchosen', $chosenAjaxSettings);
	// Allow custom values ?
	if ($allowCustom)
	{
		JFactory::getDocument()->addScriptDeclaration("
			(function($){
				$(document).ready(function () {
					// Method to add tags pressing enter
					$('" . $selector . "_chzn input').keydown(function(event) {
						// tag is greater than 3 chars and enter pressed
						if (this.value.length >= 3 && (event.which === 13 || event.which === 188)) {
							// Create the option
							var option = $('');
							option.text(this.value).val('#new#' + this.value);
							option.attr('selected','selected');
							// Add the option an repopulate the chosen field
							$('" . $selector . "').append(option).trigger('liszt:updated');
							this.value = '';
							event.preventDefault();
						}
					});
				});
			})(jQuery);
			"
		);
	}
}

Of course the K2 tag system should return the tags with the expected format.

In our field definition we will add a call to the helper in the getInput method like:

// Get the field id
$id    = isset($this->element['id']) ? $this->element['id'] : null;
$cssId = '#' . $this->getId($id, $this->element['name']);
// Load the ajax-chosen customised field JHtml::_('tag.k2tagsfield', $cssId, $this->allowCustom());

You can look at the tag field definition to see the full field definition:

libraries/cms/form/field/tag.php

6. Work in progresss

Current tag field can and should be improved. In this implementation the field only pretends to cover all the requirements with a solid base.

Suggestions and contributions are welcome. This is a mini-todo list of what you can do to help us:

Leave Comments