AngularJS Taglist with Typeahead
A directive for AngularJS that allows a list of tags to be entered, and a bootstrap typeahead to be shown when typing in tags.
HTML
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/css/bootstrap-combined.min.css">
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.2/js/bootstrap.min.js"></script>
<script src="http://code.angularjs.org/1.0.0/angular-1.0.0.js"></script>
<script src="http://code.angularjs.org/1.0.0/angular-resource-1.0.0.min.js"></script>
<script src="https://rawgit.com/pkozlowski-opensource/angularjs-mongolab/master/mongolab.js"></script>
<div ng-app="app" ng-controller="Ctrl">
<h3>Tag list with typeahead</h3>
<p>Start typing into the box to enter a tag. Typing a comma, or hitting tab when a drop-down is visible, will move on to the next tag. Clicking on the X in an existing tag will delete it. Hitting delete when there are no characters in the box will delete the last entered tag. When suggestions show up, use either the mouse or the cursor keys to select a tag.</p>
<p>If you click the "Add to Suggestions" button, your tags will be added to the MongoDB collection that holds the list of suggestions, so that next the next time you start typing a tag your suggestions will show up. (Note that the widget caches responses from the server so that you may need to refresh the page for sugestions to show up.).</p>
<typeaheadlist class="example" target="list" source="$parent.search" placeholder="eg. apples, oranges, venture capital"></typeaheadlist>
<button class="btn btn-primary" ng-click="addKeywords()">Add to Suggestions</button>
<button class="btn btn-primary" ng-click="emptyKeywords()">Clear Suggestions</button>
</div>
CSS
button {
margin-top: 10px;
}
ul {
display: inline
}
input.inline {
margin-bottom:0;
width:100px;
}
JavaScript
'use strict';
/**
* AngularJS directive for a UI element to enter tags, using Bootstrap's typeahead.
* creds: https://github.com/Jehu/Angular-Addons/blob/master/directive.autocomplete.js, https://github.com/twilson63/bstypeahead-directive
*/
var app = angular.module('app', ['mongolabResource', 'sc0ttyd.directives', 'sc0ttyd.controllers']);
app.constant('API_KEY', '33g_6AM45HadHlJ_nTSS7KwKSC_lZYcg');
app.constant('DB_NAME', 'jsfiddle');
app.factory('Keyword', function ($mongolabResource) {
return $mongolabResource('keywords');
});
angular.module('sc0ttyd.directives', []).directive('typeaheadlist', function () {
return {
restrict: 'E',
replace: true,
scope: {
source: '&'
},
template: '<div><ul class="inline"><li class="inline btn" ng-repeat="item in $parent.list">{{item}}<a href="#" onclick="angular.element(this).scope().$parent.$parent.removeArrayItem(\'list\', \'{{item}}\')"><i class="icon-remove"></i></a></li></ul><input class="inline" type="text" ng-model="model"/></div>',
link: function (scope, element, attrs) {
var inputElement = $(element).children(':last')[0];
// See http://jsfiddle.net/sc0ttyd/q7zyd/
scope.$parent.string_to_ref = function (object, reference) {
function arr_deref(o, ref, i) {
return !ref ? o : (o[ref.slice(0, i ? -1 : ref.length)]);
}
function dot_deref(o, ref) {
return !ref ? o : ref.split('[').reduce(arr_deref, o);
}
return reference.split('.').reduce(dot_deref, object);
};
// check the array to hold the items exists. if not, create it so that
// we can add stuff to it without getting a "push() is undefined" error
var target = scope.$parent.string_to_ref(scope.$parent, attrs.target);
if (typeof target === 'undefined') {
...