JSFiddle - React, Tailwind, and code Playground
by robertfalken
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.3/underscore-min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script>
<div ng-app="Tagish">
<div ng-controller="TagCtrl">
<taginput ng-model="tags"/>
</div>
</div>
CSS
.taginput {
font-family: sans-serif;
width: 200px;
border: 1px solid #eaeaea;
overflow: hidden;
padding: 10px;
margin: 30px;
}
input {
width: 50px;
float: left;
outline: none;
border: none;
font-size: 0.8em;
margin-top: 7px;
}
.tag {
background: #cbf3ff;
border: 1px solid #9dd9ea;
float: left;
margin: 4px 4px 0 0;
display: inline-block;
border-radius: 15px;
padding: 2px 6px;
font-size: 14px;
color: #629eaf;
}
.tag a {
color: #629eaf;
font-weight: bold;
font-size: 0.7em;
position: relative;
top: -1px;
}
.active {
background: #629eaf;
color: #cbf3ff;
}
JavaScript
app = angular.module("Tagish", []);
function TagCtrl($scope){
$scope.tags = ["Foo", "Bar"];
}
app.directive("taginput", function($compile,$rootScope){
return {
replace: true,
restrict: 'E',
template: "<div class='taginput'></div>",
require: "?ngModel",
link: function(scope,element,attrs,ngModel){
if (!ngModel) return;
element = $(element);
var input = $("<input type='text' placeholder='Add tag...'/>").appendTo(element);
element.click(function(){ input.focus(); });
scope.$watch(attrs.ngModel, function(tags){
element.find(".tag").remove();
_(tags).each(function(tag,index){
input.before("<span class='tag' data-index='"+index+"'>"+tag+" <a class='pictos'>x</a></span>");
});
}, true);
$(".taginput .tag a").on("click", function(e){
e.preventDefault();
var index = $(this).parent().attr("data-index");
scope.$apply(function(){ rm(index); });
});
input.keydown(function(e){
var val = input.val();
if (e.which === 13 || e.which === 188) { // return or ,
if (!val.length) return false;
var tags = ngModel.$viewValue;
var exist_at = -1;
_(tags).find(function(tag,i){
if (tag.toLowerCase() === val.toLowerCase()) {
exist_at = i;
return true;
}
});
if (exist_at >= 0) {
$("[data-index='"+exist_at+"']").not(":animated").effect("highlight");
return false;
}
scope.$apply(function(){ add(val); });
input.val("");
return false;
}
else if (e.which === 8) { // backspace
if (!val.length) {
active = element.find(".active");
if (active.size()) {
index = active.attr("data-index");
scope.$apply(function(){ rm(index); });
} else {
scope.$apply(rm);
}
...