The Joomla! Community Magazine™

Joomla! 3.1.0 Tag Field

Written by | Monday, 01 April 2013 00:00 | Published in 2013 April
This article describes how to use the new tag field added to Joomla! 3.1.0 and the new tools available for Joomla! developers.
Joomla! 3.1.0 Tag Field image by Bee Mifun at JoomlArt

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:

  • Multilanguage.
  • Nested tags structure.
  • Integrated in all the core content (using the first Unified Content Model approach seen in the core).
  • Selectable tag field mode (AJAX or nested).
  • On the fly tag creation.
  • Easily integration in any extension.

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:

  • AJAX tag search.
  • Insert custom tags pressing ENTER or the COMMA keys.
  • Use the chosen jQuery plugin as the base for the field as it was already integrated into the Joomla! core.
  • Do not edit directly the chosen plugin or any other libraries used to keep them upgradeable (except for translations).

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

  • Field searches tags while the user types them in the tag field.
  • Three min characters are required to launch the first background AJAX search.
  • The field also allows custom tag insertion writing the tag and pressing ENTER or COMMA keys. (Optional)
  • All the not existing custom tags inserted in the field are created on the fly in the database.

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

  • Displays the tags in a hierarchical view like do category selectors in other core components. 
  • Custom tags are not allowed

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:

  • minTermLength: minimum number of characters that must be typed before an ajax call is fired
  • afterTypeDelay: how many milliseconds to wait after typing stops to fire the ajax call
  • jsonTermKey: the ajax request key to use for the search query (defaults to term)

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:

  • Improve the reusability of the ajaxfield function accepting the chosenAjaxSettings as parameter.
  • Show tags in the list views of core content
  • Add the possibility to add tags directly in the list views of the core content
  • Fix a bug caused by the ENTER keydown event override that adds custom tags instead of adding highlighted tags when navigating with arrow keys.
  • Add nested tags tree on the fly. You type "motor/bikes/ducati" and the full tag tree is created.
Read 104181 times
Tagged under Developers, English
Roberto Segura

Roberto Segura

Developer from Valencia, Spain. Working with Joomla since year 2010.

  • Joomla! CMS maintainer
  • Member of the Joomla! Bug Squad
  • Contributor of opensource projects like Twitter Bootstrap, Prestashop, K2, Joostrap, FOF..
  • jQuery lover
  • I require git to live

Latest from Roberto Segura