tagInput: A simple jQuery plugin for tag entry using Bootstrap 4
by johna | October 15, 2019 | Jquery/Javascript Web Development
For a recent website project I needed a way to enter multiple tags.
I tried a few open-source scripts but didn't find something that suited my needs. Some had browser compatibility, some had other issues, and some were huge!
I just wanted something simple that I could easily modify to suit my own needs, so I wrote my own.
My requirements:
• Progressive enhancement (if JavaScript is not available or not working, revert to a simple input text for data entry instead)
• Not allow duplicate tags
• Use Bootstrap 4.x classes
• Validate entered tags
• Autocomplete functionality using HTML 5 datalist
• Autocomplete from an AJAX data source
Demo
Update history
v1.0 - Initial release
v1.1 - Restricted minimum and maximum length of tags, handled tab key (can add tag, or if input text empty then moves to next field), added public method to add tags
v1.2 - Handled enter key or click on datalist option
//tagInput by John Avis Oct 16, 2019
//v1.2
(function ($, win) {
$.fn.tagInput = function () {
return this.each(function () {
//Single function used to add tags
function addTag(tagName) {
var cleanTagName = tagName.trim();
if (cleanTagName != '') {
//Input validation (this example allows minimum 2 and maximum 50 upper and lower case letters and numbers - change if required)
if (/^([a-zA-Z0-9]){2,50}$/.test(cleanTagName) === false) {
return '2-50 letters or numbers only';
}
//Check for duplicates (remove if not required)
var tags = el.val().split(",");
var rawTagName = rawTag(cleanTagName)
for (var i = 0; i < tags.length; i++) {
if (rawTag(tags[i]) === rawTagName) {
return 'Duplicate tag';
}
}
//check for maximum number of tags reached
if (tags.length >= 10) {
return 'Only 10 tags allowed';
}
//Add a tag to the list
el.val(el.val() + (el.val() !== '' ? ',' : '') + cleanTagName);
$('#' + id + '_form').before('<div class="float-left mr-1 mb-1"><span class="btn btn-secondary btn-sm">' + cleanTagName + ' <button type="button" class="btn badge badge-light" value="' + cleanTagName + '">×</a></span></div>');
return true;
}
}
function rawTag(tagName) {
//Compare tags by their raw values only by converting to lower case//
//You may also use this to remove any non alpha-numeric characters (if allowed) if some characters are ignored for comparisons
return tagName.toLowerCase();
}
//Global variables - the element (jquery object) itself, and the ID which is used as a prefix for dynamic elements
var el = $(this);
var id = el.attr('id');
//Add a reference to the object as data
el.data('tagInput', this);
//Hide the original input text
el.hide();
//Create the HTML elements for displaying the list of tags and for entering a new tag
el.after('<div id="' + id + '_list" class="clearfix border rounded pl-1 pt-1">' +
'<div id="' + id + '_form" class="float-left mb-1">' +
'<input id="' + id + '_input" type="text" autocomplete="off" class="form-control form-control-sm" maxlength="50" list="' + id + '_datalist" placeholder="Enter a tag" />' +
'<div id="' + id + '_error" class="text-danger small" style="display:none"></div>' +
'<button id="' + id + '_add" class="btn btn-outline-secondary sr-only" type="button">Add tag</button>' +
'</div>' +
'</div>' +
'<datalist id="' + id + '_datalist"></datalist>');
//Attempt to add any existing comma separated values from the input text (can change separator if required)
var tags = el.val().split(",");
el.val('');
for (var i = 0; i < tags.length; i++) {
addTag(tags[i]);
}
var lastVal = '';
//Watch for blur and keyup
$('#' + id + '_input').bind('blur keyup', function (e) {
//Empty and hide any existing validation error
$('#' + id + '_error').html('').hide();
//Execute if blur event or enter key pressed (could also trap other keystrokes if required)
if (e.type === 'blur' || (e.type === 'keyup' && (typeof e.keyCode === 'undefined' || e.keyCode === 13 || (e.shiftKey === false && e.keyCode === 9)))) {
//Empty and hide any existing validation error
$('#' + id + '_error').html('').hide();
//Attempt to add the tag and store the result
var result = addTag($(this).val());
if (result === true) {
//If was successful then clear the input text and autocomplete datalist
$(this).val('');
$('#' + id + '_datalist').html('');
//If enter or tab key was pressed then set focus back to input text
if (e.type === 'keyup' && (typeof e.keyCode === 'undefined' || e.keyCode === 13 || (e.shiftKey === false && e.keyCode === 9))) {
$(this).focus();
}
}
else {
$('#' + id + '_error').html(result).show();
}
}
//Autocomplete datalist is only populated if at least one character has been entered (change if required)
else if ($(this).val().length < 1) {
//Less than 1 charcters so make sure the datalist is empty
$('#' + id + '_datalist').html('');
}
//Execute if more than one character has been entered, will populate the datalist with matches
else if (lastVal != $(this).val().trim()) {
//Empty the datalist
$('#' + id + '_datalist').html('');
//Populate the datalist with dummy data (the first letter entered plus numbers 0 to 50)
//Replace with an AJAX request or remove if not required
for (i = 0; i < 50; i++) {
$('#' + id + '_datalist').append('<option>' + $(this).val().substring(0, 1) + i + '</option>');
}
}
lastVal = $(this).val().trim();
});
//Prevent the enter key from submitting the form, and prevent tab key default action if input text has data
$('#' + id + '_input').bind('keydown', function (e) {
if (e.keyCode === 13 || (e.shiftKey === false && e.keyCode === 9 && $(this).val().trim() !== '')) {
e.preventDefault();
return false;
}
});
//Watch for delete tag button pressed
$('#' + id + '_list').on('click', '.badge', function () {
//Get current tags
var tags = el.val().split(',');
//Clear current values, ready to add all but the deleted tag
el.val('');
//Iterate through current tags and add all but the deleted tag
for (var i = 0; i < tags.length; i++) {
if (tags[i] != $(this).val()) {
el.val(el.val() + (el.val() !== '' ? ',' : '') + tags[i]);
}
}
//Remove the deleted tag element
$(this).parent().parent().remove();
//Set focus back to the input text
el.focus();
});
//A public method for adding extra tags
this.addTags = function (tagNames) {
var tags = tagNames.split(',');
for (var i = 0; i < tags.length; i++) {
addTag(tags[i]);
}
}
});
};
}(jQuery, window));
Related Posts
Converting dBase IV programs to run in the browser
by johna | September 13, 2024
Some pointless entertainment trying to get some old dBase programs running in the browser.
How to set up a debugging using the Turnkey Linux LAMP stack and VS Code
by johna | December 19, 2023
The second part in my guide to setting up a website and database using the Turnkey Linux LAMP stack.
How to set up a website and database using the Turnkey Linux LAMP stack
by johna | November 18, 2023
If you need to host your own website for the purposes of web development, Turnkey Linux LAMP Stack is an easy to install all-in-one solution that you can set up on a spare computer or a VM (Virtual Machine).
Comments
There are no comments yet. Be the first to leave a comment!