10

I am trying to use Bootstrap Tags Input plugin without Typeahead. I have included following files:

<link href="../../bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="../../tagsinput/css/bootstrap-tagsinput.css" rel="stylesheet" type="text/css">
<script src="../../tagsinput/js/bootstrap-tagsinput.min.js"></script>

The script is as below:

<script>
    $('#tagPlaces').tagsinput({
        allowDuplicates: true
    });
</script>

Part of JSP form where using the plugin:

<div class="form-group">
        <label for="tagPlaces" class="col-sm-2 control-label">Tag Places</label>
        <div class="col-sm-10">
            <input type="text" class="form-control" data-role="tagsinput" id="tagPlaces">
        </div>
</div>

But I am not able to see the tags in the input field. Also my form is getting submitted as I press enter for the tag. Please suggest what am I missing and what is the correct way of using the plugin.

Aman
  • 879
  • 3
  • 9
  • 22

2 Answers2

22

This is how i did it

<script src="../js/bootstrap-tagsinput.js"></script>
no more javascript

Css
You can include the original bootstrap tags input css file

<link rel="stylesheet" href="../css/bootstrap-tagsinput.css">

Or you can just use only this

.bootstrap-tagsinput {
    background-color: #fff;
    border: 1px solid #ccc;
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
    display: block;
    padding: 4px 6px;
    color: #555;
    vertical-align: middle;
    border-radius: 4px;
    max-width: 100%;
    line-height: 22px;
    cursor: text;
}
.bootstrap-tagsinput input {
    border: none;
    box-shadow: none;
    outline: none;
    background-color: transparent;
    padding: 0 6px;
    margin: 0;
    width: auto;
    max-width: inherit;
}

And HTML

<input type="text" value="" data-role="tagsinput" id="tags" class="form-control">
Tonza
  • 620
  • 8
  • 16
  • 3
    First, this answer helped me immensely get tags-input working on my page and did provide an upvote. I wanted to share a quick observation though. The example above does work to show the tags; however, the CSS is missing the selector data-remove. As a result, the code above doesn't show the "X" to remove a tag. The OP did not voice a need for the X but I wanted to share my experience. – HPWD Mar 27 '18 at 20:52
  • You can use limitless js for the full control – Capan Jul 31 '19 at 13:00
2

This solution does not use the plugin but worked even better for me.

$(function() {
 $('#form-tags-1').tagsInput();

 $('#form-tags-2').tagsInput({
  'onAddTag': function(input, value) {
   console.log('tag added', input, value);
  },
  'onRemoveTag': function(input, value) {
   console.log('tag removed', input, value);
  },
  'onChange': function(input, value) {
   console.log('change triggered', input, value);
  }
 });

 $('#form-tags-3').tagsInput({
  'unique': true,
  'minChars': 2,
  'maxChars': 10,
  'limit': 5,
  'validationPattern': new RegExp('^[a-zA-Z]+$')
 });

 $('#form-tags-4').tagsInput({
  'autocomplete': {
   source: [
    'apple',
    'banana',
    'orange',
    'pizza'
   ]
  }
 });

 $('#form-tags-5').tagsInput({
  'delimiter': ';'
 });

 $('#form-tags-6').tagsInput({
  'delimiter': [',', ';']
 });
});



/* jQuery Tags Input Revisited Plugin
 *
 * Copyright (c) Krzysztof Rusnarczyk
 * Licensed under the MIT license */

(function($) {
 var delimiter = [];
 var inputSettings = [];
 var callbacks = [];

 $.fn.addTag = function(value, options) {
  options = jQuery.extend({
   focus: false,
   callback: true
  }, options);
  
  this.each(function() {
   var id = $(this).attr('id');

   var tagslist = $(this).val().split(_getDelimiter(delimiter[id]));
   if (tagslist[0] === '') tagslist = [];

   value = jQuery.trim(value);
   
   if ((inputSettings[id].unique && $(this).tagExist(value)) || !_validateTag(value, inputSettings[id], tagslist, delimiter[id])) {
    $('#' + id + '_tag').addClass('error');
    return false;
   }
   
   $('<span>', {class: 'tag'}).append(
    $('<span>', {class: 'tag-text'}).text(value),
    $('<button>', {class: 'tag-remove'}).click(function() {
     return $('#' + id).removeTag(encodeURI(value));
    })
   ).insertBefore('#' + id + '_addTag');

   tagslist.push(value);

   $('#' + id + '_tag').val('');
   if (options.focus) {
    $('#' + id + '_tag').focus();
   } else {
    $('#' + id + '_tag').blur();
   }

   $.fn.tagsInput.updateTagsField(this, tagslist);

   if (options.callback && callbacks[id] && callbacks[id]['onAddTag']) {
    var f = callbacks[id]['onAddTag'];
    f.call(this, this, value);
   }
   
   if (callbacks[id] && callbacks[id]['onChange']) {
    var i = tagslist.length;
    var f = callbacks[id]['onChange'];
    f.call(this, this, value);
   }
  });

  return false;
 };

 $.fn.removeTag = function(value) {
  value = decodeURI(value);
  
  this.each(function() {
   var id = $(this).attr('id');

   var old = $(this).val().split(_getDelimiter(delimiter[id]));

   $('#' + id + '_tagsinput .tag').remove();
   
   var str = '';
   for (i = 0; i < old.length; ++i) {
    if (old[i] != value) {
     str = str + _getDelimiter(delimiter[id]) + old[i];
    }
   }

   $.fn.tagsInput.importTags(this, str);

   if (callbacks[id] && callbacks[id]['onRemoveTag']) {
    var f = callbacks[id]['onRemoveTag'];
    f.call(this, this, value);
   }
  });

  return false;
 };

 $.fn.tagExist = function(val) {
  var id = $(this).attr('id');
  var tagslist = $(this).val().split(_getDelimiter(delimiter[id]));
  return (jQuery.inArray(val, tagslist) >= 0);
 };

 $.fn.importTags = function(str) {
  var id = $(this).attr('id');
  $('#' + id + '_tagsinput .tag').remove();
  $.fn.tagsInput.importTags(this, str);
 };

 $.fn.tagsInput = function(options) {
  var settings = jQuery.extend({
   interactive: true,
   placeholder: 'Add a tag',
   minChars: 0,
   maxChars: null,
   limit: null,
   validationPattern: null,
   width: 'auto',
   height: 'auto',
   autocomplete: null,
   hide: true,
   delimiter: ',',
   unique: true,
   removeWithBackspace: true
  }, options);

  var uniqueIdCounter = 0;

  this.each(function() {
   if (typeof $(this).data('tagsinput-init') !== 'undefined') return;

   $(this).data('tagsinput-init', true);

   if (settings.hide) $(this).hide();
   
   var id = $(this).attr('id');
   if (!id || _getDelimiter(delimiter[$(this).attr('id')])) {
    id = $(this).attr('id', 'tags' + new Date().getTime() + (++uniqueIdCounter)).attr('id');
   }

   var data = jQuery.extend({
    pid: id,
    real_input: '#' + id,
    holder: '#' + id + '_tagsinput',
    input_wrapper: '#' + id + '_addTag',
    fake_input: '#' + id + '_tag'
   }, settings);

   delimiter[id] = data.delimiter;
   inputSettings[id] = {
    minChars: settings.minChars,
    maxChars: settings.maxChars,
    limit: settings.limit,
    validationPattern: settings.validationPattern,
    unique: settings.unique
   };

   if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
    callbacks[id] = [];
    callbacks[id]['onAddTag'] = settings.onAddTag;
    callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
    callbacks[id]['onChange'] = settings.onChange;
   }

   var markup = $('<div>', {id: id + '_tagsinput', class: 'tagsinput'}).append(
    $('<div>', {id: id + '_addTag'}).append(
     settings.interactive ? $('<input>', {id: id + '_tag', class: 'tag-input', value: '', placeholder: settings.placeholder}) : null
    )
   );

   $(markup).insertAfter(this);

   $(data.holder).css('width', settings.width);
   $(data.holder).css('min-height', settings.height);
   $(data.holder).css('height', settings.height);

   if ($(data.real_input).val() !== '') {
    $.fn.tagsInput.importTags($(data.real_input), $(data.real_input).val());
   }
   
   // Stop here if interactive option is not chosen
   if (!settings.interactive) return;
   
   $(data.fake_input).val('');
   $(data.fake_input).data('pasted', false);
   
   $(data.fake_input).on('focus', data, function(event) {
    $(data.holder).addClass('focus');
    
    if ($(this).val() === '') {
     $(this).removeClass('error');
    }
   });
   
   $(data.fake_input).on('blur', data, function(event) {
    $(data.holder).removeClass('focus');
   });

   if (settings.autocomplete !== null && jQuery.ui.autocomplete !== undefined) {
    $(data.fake_input).autocomplete(settings.autocomplete);
    $(data.fake_input).on('autocompleteselect', data, function(event, ui) {
     $(event.data.real_input).addTag(ui.item.value, {
      focus: true,
      unique: settings.unique
     });
     
     return false;
    });
    
    $(data.fake_input).on('keypress', data, function(event) {
     if (_checkDelimiter(event)) {
      $(this).autocomplete("close");
     }
    });
   } else {
    $(data.fake_input).on('blur', data, function(event) {
     $(event.data.real_input).addTag($(event.data.fake_input).val(), {
      focus: true,
      unique: settings.unique
     });
     
     return false;
    });
   }
   
   // If a user types a delimiter create a new tag
   $(data.fake_input).on('keypress', data, function(event) {
    if (_checkDelimiter(event)) {
     event.preventDefault();
     
     $(event.data.real_input).addTag($(event.data.fake_input).val(), {
      focus: true,
      unique: settings.unique
     });
     
     return false;
    }
   });
   
   $(data.fake_input).on('paste', function () {
    $(this).data('pasted', true);
   });
   
   // If a user pastes the text check if it shouldn't be splitted into tags
   $(data.fake_input).on('input', data, function(event) {
    if (!$(this).data('pasted')) return;
    
    $(this).data('pasted', false);
    
    var value = $(event.data.fake_input).val();
    
    value = value.replace(/\n/g, '');
    value = value.replace(/\s/g, '');
    
    var tags = _splitIntoTags(event.data.delimiter, value);
    
    if (tags.length > 1) {
     for (var i = 0; i < tags.length; ++i) {
      $(event.data.real_input).addTag(tags[i], {
       focus: true,
       unique: settings.unique
      });
     }
     
     return false;
    }
   });
   
   // Deletes last tag on backspace
   data.removeWithBackspace && $(data.fake_input).on('keydown', function(event) {
    if (event.keyCode == 8 && $(this).val() === '') {
      event.preventDefault();
      var lastTag = $(this).closest('.tagsinput').find('.tag:last > span').text();
      var id = $(this).attr('id').replace(/_tag$/, '');
      $('#' + id).removeTag(encodeURI(lastTag));
      $(this).trigger('focus');
    }
   });

   // Removes the error class when user changes the value of the fake input
   $(data.fake_input).keydown(function(event) {
    // enter, alt, shift, esc, ctrl and arrows keys are ignored
    if (jQuery.inArray(event.keyCode, [13, 37, 38, 39, 40, 27, 16, 17, 18, 225]) === -1) {
     $(this).removeClass('error');
    }
   });
  });

  return this;
 };
 
 $.fn.tagsInput.updateTagsField = function(obj, tagslist) {
  var id = $(obj).attr('id');
  $(obj).val(tagslist.join(_getDelimiter(delimiter[id])));
 };

 $.fn.tagsInput.importTags = function(obj, val) {
  $(obj).val('');
  
  var id = $(obj).attr('id');
  var tags = _splitIntoTags(delimiter[id], val); 
  
  for (i = 0; i < tags.length; ++i) {
   $(obj).addTag(tags[i], {
    focus: false,
    callback: false
   });
  }
  
  if (callbacks[id] && callbacks[id]['onChange']) {
   var f = callbacks[id]['onChange'];
   f.call(obj, obj, tags);
  }
 };
 
 var _getDelimiter = function(delimiter) {
  if (typeof delimiter === 'undefined') {
   return delimiter;
  } else if (typeof delimiter === 'string') {
   return delimiter;
  } else {
   return delimiter[0];
  }
 };
 
 var _validateTag = function(value, inputSettings, tagslist, delimiter) {
  var result = true;
  
  if (value === '') result = false;
  if (value.length < inputSettings.minChars) result = false;
  if (inputSettings.maxChars !== null && value.length > inputSettings.maxChars) result = false;
  if (inputSettings.limit !== null && tagslist.length >= inputSettings.limit) result = false;
  if (inputSettings.validationPattern !== null && !inputSettings.validationPattern.test(value)) result = false;
  
  if (typeof delimiter === 'string') {
   if (value.indexOf(delimiter) > -1) result = false;
  } else {
   $.each(delimiter, function(index, _delimiter) {
    if (value.indexOf(_delimiter) > -1) result = false;
    return false;
   });
  }
  
  return result;
 };
 
 var _checkDelimiter = function(event) {
  var found = false;
  
  if (event.which === 13) {
   return true;
  }

  if (typeof event.data.delimiter === 'string') {
   if (event.which === event.data.delimiter.charCodeAt(0)) {
    found = true;
   }
  } else {
   $.each(event.data.delimiter, function(index, delimiter) {
    if (event.which === delimiter.charCodeAt(0)) {
     found = true;
    }
   });
  }
  
  return found;
  };
  
  var _splitIntoTags = function(delimiter, value) {
   if (value === '') return [];
   
   if (typeof delimiter === 'string') {
    return value.split(delimiter);
   } else {
    var tmpDelimiter = '∞';
    var text = value;
    
    $.each(delimiter, function(index, _delimiter) {
     text = text.split(_delimiter).join(tmpDelimiter);
    });
    
    return text.split(tmpDelimiter);
   }
   
   return [];
  };
})(jQuery);
*{box-sizing: border-box;}
html{height: 100%;margin: 0;}
body{min-height: 100%;font-family: 'Roboto';margin: 0;background-color: #fafafa;}
.container { margin: 150px auto; max-width: 960px;}
label{display: block;padding: 20px 0 5px 0;}
.tagsinput,.tagsinput *{box-sizing:border-box}
.tagsinput{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;background:#fff;font-family:sans-serif;font-size:14px;line-height:20px;color:#556270;padding:5px 5px 0;border:1px solid #e6e6e6;border-radius:2px}
.tagsinput.focus{border-color:#ccc}
.tagsinput .tag{position:relative;background:#556270;display:block;max-width:100%;word-wrap:break-word;color:#fff;padding:5px 30px 5px 5px;border-radius:2px;margin:0 5px 5px 0}
.tagsinput .tag .tag-remove{position:absolute;background:0 0;display:block;width:30px;height:30px;top:0;right:0;cursor:pointer;text-decoration:none;text-align:center;color:#ff6b6b;line-height:30px;padding:0;border:0}
.tagsinput .tag .tag-remove:after,.tagsinput .tag .tag-remove:before{background:#ff6b6b;position:absolute;display:block;width:10px;height:2px;top:14px;left:10px;content:''}
.tagsinput .tag .tag-remove:before{-webkit-transform:rotateZ(45deg);transform:rotateZ(45deg)}
.tagsinput .tag .tag-remove:after{-webkit-transform:rotateZ(-45deg);transform:rotateZ(-45deg)}
.tagsinput div{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}
.tagsinput div input{background:0 0;display:block;width:100%;font-size:14px;line-height:20px;padding:5px;border:0;margin:0 5px 5px 0}
.tagsinput div input.error{color:#ff6b6b}
.tagsinput div input::-ms-clear{display:none}
.tagsinput div input::-webkit-input-placeholder{color:#ccc;opacity:1}
.tagsinput div input:-moz-placeholder{color:#ccc;opacity:1}
.tagsinput div input::-moz-placeholder{color:#ccc;opacity:1}
.tagsinput div input:-ms-input-placeholder{color:#ccc;opacity:1}
<!doctype html>
<html lang="en">
 <head>
     <title>Responsive Tags Input</title>
        <link href="https://www.jqueryscript.net/css/jquerysctipttop.css" rel="stylesheet" type="text/css">
  <script src="http://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
  <link rel="stylesheet" href="http://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    </head>
    <body>
        <div class="container">
         <form id="form">
          <h2 class="text-center" style="margin-bottom:25px;">Responsive Tags Input With Autocomplete Examples</h2>
          <label>Simple tags input:</label>
          <input id="form-tags-1" name="tags-1" type="text" value="jQuery,Script,Net">
        
          <label>Tags input with callbacks (check console):</label>
          <input id="form-tags-2" name="tags-2" type="text" value="apple,banana,pizza">
        
          <label>Tags input with various validation:</label>
          <input id="form-tags-3" name="tags-3" type="text" value="">
         </form>
        </div>
    </body>
</html>

Original post: https://bootsnipp.com/snippets/exqd3

Tumelo Mapheto
  • 141
  • 1
  • 5