tags manager, tags, jquery plugin, tag handler, bootstrap

WellDoneThings.com

Little (hopefully) well designed pieces of code I want to share with you.

Tags Manager (a jQuery plugin)

Type some tags in the input field, and separate them with enter, comma, or tab:

Turn a simple input field into a tags manager with a line of code:

HTML markup

<input type="text" name="tags" placeholder="Tags" class="tm-input"/>

Javascript

jQuery(".tm-input").tagsManager();

Using multiple tag manager instances on the same page

Note when using multiple instances of tag manager on a page, each input field must have a unique name, not just a unique ID. This behavior will be improved in v3.0

Retrieving tags on <form> submit

By default, Tag Manager creates a hidden input field (based on the name of the input) and stores its data in the hidden field as a comma separated list.

When processing the user input on form submit, simply parse the data of this hidden field.

Look for this hidden field in the examples above using a browser developer tool (such as Firefox Firebug). In the example you should see: <input type="hidden" value="Pisa,Rome" name="hiddenTagListA">

It is also possible to give this field a customer name using the hiddenTagListName parameter, or create your own hidden field and use the hiddenTagListId parameter.

Pushing Tags via Ajax

Tags Manager can push entered tag values on-the-fly via Ajax as the user creates/deletes tags to a user-specified destination. Use the AjaxPushAllTags option to push all tag values on every update, rather than incrementally per created tag. Use the AjaxPushParameters option to add additional parameters on each ajax request. Refer to documentation for additional parameters.

    jQuery(".tm-input").tagsManager({
        AjaxPush: '/ajax/countries/push',
        AjaxPushAllTags: true,
        AjaxPushParameters: { 'authToken': 'foobar' }
    });
  

Typeahead via Ajax source

Tags Manager can be used in combination with the Bootstrap Typeahead library. (In a future version we will support Twitter Typeahead.js)

    jQuery(".tm-input").tagsManager({
        typeahead: true,
        typeaheadAjaxSource: '/ajax/countries',
        typeaheadAjaxPolling: true
    });
  

Typeahead via function() source

Type some tags in the input field, separate them with comma (or tab).

The code below show how to use an ajax source, and an ajax destination for any added tag:

    jQuery(".tm-input").tagsManager({
        typeahead: true,
        typeaheadSource: your_function_here(),
        blinkBGColor_1: '#FFFF9C',
        blinkBGColor_2: '#CDE69C',
    });
  

Tags Manager Configuration

The code below show all the configurable options available (as of version 2.4.1):

    jQuery(".tm-input").tagsManager({
        prefilled: ["Pisa", "Rome"],
        CapitalizeFirstLetter: true,
        preventSubmitOnEnter: true,
        isClearInputOnEsc: true,
        typeahead: true,
        typeaheadAjaxMethod: "GET",
        typeaheadAjaxSource: null,
        typeaheadSource: ["Pisa", "Rome", "Milan", "Florence", "New York", "Paris", "Berlin", "London", "Madrid"],
        typeaheadAjaxPolling: false,
        typeaheadDelegate: {},
        AjaxPush: null,
        AjaxPushAllTags: null,
        AjaxPushParameters: null,
        delimiters: [9, 13, 44],
        backspace: [8]
        blinkBGColor_1: '#FFFF9C',
        blinkBGColor_2: '#CDE69C',
        hiddenTagListName: 'hiddenTagListA',
        hiddenTagListId: null,
        deleteTagsOnBackspace: true,
        tagsContainer: null,
        tagCloseIcon: '×',
        tagClass: '',
        validator: null,
        onlyTagList: false
    });
  
prefilled Populates the initial tag values. Default: null. Allowed formats:
  • an Array of strings
  • a String delimited by the first char code in the delimiters parameter (comma by default)
  • a Function which returns an array
  • if prefill is not provided hiddenTagListId will be used as a fallback if provided. Note the value in hiddenTagListId should be a string delimited by the first char code in the delimiters parameter (comma by default)
CapitalizeFirstLetter If true, all tags will be displayed with first letter capitalized. Default: false.
preventSubmitOnEnter Deprecated (v2.4.0) Will be hardcoded to true in v3.0.
If true, hitting the enter key inside the input field, then it's associated form will not be submitted. Note that this is different than using enter as a tag separator (see delimiters parameter.) Default: true.
isClearInputOnEsc Deprecated (v2.4.0) Will be hardcoded to true in v3.0.
If true, hitting the esc key inside the input field will clear its value. Default: true.
typeahead If true a Bootstrap typeahead is setup, typeahead is a nice plugin for bootstrap, when the user start typing something a popup below the input field show possible values matching the typed text.
Currently this features is available only if you also include bootstrap, if you are not using it tags manager typeahead won't work. Should be relatively easy to replace typeahead with jQuery UI autocomplete for the ones not using bootstrap, but I didn't. If anyone is really interested I can consider including that in a next releas that.
If you choose to use typeahead please check the typeahead specific paramenters in the bootstrap documentation.
And in case you don't want browsers autocomplete to mess with your own autocomplete learn to add autocomplete="off" on every Tags Manager input field.
typeaheadAjaxMethod Method to retrieve typeahead values by Ajax. Allowed: "POST" or "GET". Default: "POST"
typeaheadAjaxSource If you are a fan of bootstrap typeahead plugin you may love this, is a JSON AJAX source for the list of possible values to display in the typeahead popup. The JSON returned by your serverside code should look like this: {"tags":[{"tag":"Pisa"},{"tag":"Rome"},{"tag":"Milan"},{"tag":"Florence"},{"tag":"New York"},{"tag":"Paris"},{"tag":"Berlin"},{"tag":"London"},{"tag":"Madrid"}]}
typeaheadSource This is passed to standard Bootstrap typeahead source initialization option, so if you don't need an AJAX dynamically generated list you can provide a static one, or you can pass a function(), see typeahead docs for details. Of course in your very function() you can do ajax or whatever you want.
typeaheadAjaxPolling With Bootstrap v2.0 typeahead can request the list of entries to show to an ajax source everytime the user type something in the input field, provide "true" to this option to activate it. Otherwise the ajax source will be queried only at initialization.
typeaheadDelegate Options to be passed directly to the underlying Bootstrap typeahead object. Default: none.
AjaxPush Well, since we pull from an ajax source we can also push, don't we? So provide a url as AjaxPush and the added tag will be POSTed.
AjaxPushAllTags If true, enables a mode to sync the entire tag state via AJAX (rather than incrementally) each time a tag is added/deleted. Default: false.
AjaxPushParameters Adds an additional parameter payload to push with each AJAX request, for example server authenication parameters. Default: null.
delimiters Default: [9,13,44] (tab, enter, comma). Delimiters should be numeric ASCII char codes. Please note the following:
  • The following values are handled as key codes: 9 (tab), 13 (enter), 16 (shift), 17 (ctrl), 18 (alt), 19 (pause/break), 37 (leftarrow), 38 (uparrow), 39 (rightarrow), 40 (downarrow)
  • Note that codes 45 (key = insert, char = -) and 46 (key = delete, char = .) are handled as chars, so currently insert and delete keys cannot be used as delimiters
  • The first char code (non-key code) specified in the array will be used as the base delimiter for parsing tags to/from the hidden field "list string". This will default to comma if not specified.
  • See http://unixpapa.com/js/key.html for a full explanation of ASCII versus key codes.
delimeters Deprecated (v2.4.0) Incorrect spelling of delimiters; same function as delimiters
backspace When the input field is empty, and some tags are rendered on the left of the input field, and the user hit the backspace the plugin remove the rightest tag (which is the last the user entered).
With this option you can provide an array of char codes (like the delimiters above) you want the system to use in place of the backspace (char code 8), or provide an empty array if you don't want this feature at all.
blinkBGColor_1
blinkBGColor_2
When a duplicate tag is entered the user is notified with a blinking of the corresponding (duplicate) tag, here you can configure the colors.
hiddenTagListName Deprecated (v2.4.0) Usage will be replaced in 3.0 with hiddenTagListId.
Define a custom name for the hidden tags input field which stores the tag values. Default: 'hidden-' + the name of the tag input field
Note if you have multiple instance of TagManager in a form you SHOULD give a different name to each hidden tags list field!
hiddenTagListId If you wish to use your own explicitly defined hidden field to store tags
deleteTagsOnBackspace Deprecated (v2.4.0) Will be hardcoded to true in v3.0; backspace will be continued to be supported.
If true, using the keys defined in the backspace parameter will delete the most recent tag if the input cursor is at the beginning of the field. Default: true.
maxTags Optionally defines the maximum number of tags accepted. Default: 0 (no limit)
tagCloseIcon Sets the HTML string to be used as the tag close icon. Default: ×
tagsContainer Optional jQuery selector for the element to contain the tags. Default: tags appear immediately before the tag input.
tagClass Optional class to be applied to all tags. Please as see note about automatic tag styling. Default: none
validator An optional callback function to validate the user input. Takes the tag string as input, and must return true or false. Default: null (no validation function used).
onlyTagList If true, rejects tags which do not appear in the typeahead list. Default: false

Tag Manager Methods

You can pop the last added tag (the rightmost being show)

.tagsManager('popTag');

You can push a new tag

.tagsManager('pushTag','I_am_a_new_tag');

You can remove all tags

.tagsManager('empty');

Tag Manager Styles

Tag Manager comes bundled with a Bootstrap-themed set semantic colors/sizes, and provides multiple methods to define tag styles:

  1. the CSS base class tm-tag is applied to all tags
  2. classes assigned to the input are used to infer the semantic tag classes, for example <input class='tm-input tm-input-success tm-input-small'/> will apply classes tm-tag-success and tm-tag-small to the tags.
  3. you can apply a custom class(es) to the tags using the tagClass parameter

In order to have correct alignment we recommend that you give the input the class tm-tag. If using TagManager within a Bootstrap control-group container, please also add tm-group class to the container node.

History

I built Tags Manager while working on an online personal finance tool, I wanted a simple solution to manage tags for each expense users were entering, like in stackoverflow and many other sites.

Alternatives to my Tags Manager

Before to develop my own tags manager I spent quite a lot of time investigating what other solutions where available, so I think I can spare you some time listing them here and explaining why I developed my own.

The four above are the best around in my opinion, but... I developed Tags Manager. I wanted it to be very simple, I didn't need a pencil mouse pointer when the user hover it. I didn't need inplace edit of the tag, I think it's confusing for the user. I didn't want the tag manager to generate a lot of html in the form.

And I wanted it to be fully integrated with bootstrap and its typeahead.

Version 3.0 in Development

Bootstrap 3, due out in mid-2013, will replace the Bootstrap Typeahead module with Twitter Typeahead.js. Correspondingly, TagsManager will be begin it's own v3.0 upgrade which will support Twitter Typeahead.js exclusively. As Twitter Typeahead.js is more feature-rich, we will remove much of the Typeahead and Ajax layers in favor of native Typeahead.js functionality.

Third-Party Add-ons

Further reading

If you have choosen to go this way and implement a tags system in one of your application you have probably already thought about a couple of things, like the database structure required to store tags.

But just in case... You can find some thoughts about that here.

Check the Tags Manager repository and download the scripts from github

Download from GitHub

Comments are welcome!