Skip to content

Commit

Permalink
Merge pull request #24 from dwalters/new-angular-directive
Browse files Browse the repository at this point in the history
Add bsTagsInput angular directive & example for bootstrap3 with typeahea...
  • Loading branch information
timschlechter committed Oct 5, 2013
2 parents 7f07222 + 32f71eb commit 3c8ed65
Show file tree
Hide file tree
Showing 4 changed files with 246 additions and 46 deletions.
12 changes: 11 additions & 1 deletion examples/assets/app_bs3.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,14 @@ elt.tagsinput('input').typeahead({
}).bind('typeahead:selected', $.proxy(function (obj, datum) {
this.tagsinput('add', datum);
this.tagsinput('input').typeahead('setQuery', '');
}, elt));
}, elt));

angular.module('AngularExample', ['bsTagsInput'])
.controller('Ctrl',
function Ctrl($scope) {
$scope.tags = ['Amsterdam', 'Washington'];
$scope.tagsTypeahead = {
local: ['Sydney', 'Beijing', 'Cairo']
};
}
);
108 changes: 108 additions & 0 deletions examples/assets/bsTagsInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
angular.module('bsTagsInput', [])
/**
* @ngdoc directive
* @name bsTagsInput
* @restrict A
*
* @description
* Sets up an input field for tag inputs, using the bootstrap-tagsinput jQuery plugin.
*
* @element INPUT or SELECT
* @param {Object} options passed to the bootstrap-tagsinput plugin at initialization.
*
* @example
<doc:example>
<doc:source>
<script>
function Ctrl($scope) {
$scope.tags = ['Amsterdam', 'Washington'];
$scope.tagsTypeahead = {
local: ['Sydney', 'Beijing', 'Cairo']
}
}
</script>
<form ng-controller="Ctrl">
<input type="text" ng-model="tags" bs-tags-input bs-tags-typeahead="tagsTypeahead">
<pre>{{tags}}</pre>
</form>
</doc:source>
</doc:example>
*/
.directive('bsTagsInput', function() {
// reference to underscorejs/lodash difference method
var difference;
if (typeof(_) !== 'undefined') {
difference = _.difference;
} else {
// fallback to a naive implementation
difference = function(array, other) {
var results = [];
angular.forEach(array, function(value) {
if (other.indexOf(value) === -1) {
results.push(value);
}
});
return results;
};
}

return {
require: 'ngModel',
controller: function() {
},
link: function(scope, element, attrs, ngModelCtrl) {
// initialize tagsinput
var options = scope.$eval(attrs.bsTagsInput) || {};
element.tagsinput(options);

// handle changes from the underlying model
ngModelCtrl.$render = function() {
var oldVal = element.tagsinput('items'),
newVal = ngModelCtrl.$viewValue;
difference(oldVal, newVal).forEach(function(item) {
element.tagsinput('remove', item, true);
});
difference(newVal, oldVal).forEach(function(item) {
element.tagsinput('add', item, true);
});
};

// handle changes from the UI
element.on('change', function() {
var items = element.tagsinput('items');
ngModelCtrl.$setViewValue(items);
});

// handle cleanup
scope.$on('$destroy', function() {
element.tagsinput('destroy');
});
}
};
})
/**
* @ngdoc directive
* @name bsTagsTypeahead
* @restrict A
*
* @description
* Using typeahead.js, adds autocompletion support to a bsTagsInput field.
*
* @element INPUT or SELECT
* @param {Object} options passed to the typeahead.js plugin.
*/
.directive('bsTagsTypeahead', function() {
return {
require: 'bsTagsInput',
link: function(scope, element, attrs, bsTagsInputCtrl) {
// setup typeahead on the 'input' element
var options = scope.$eval(attrs.bsTagsTypeahead) || {};
element.tagsinput('input')
.typeahead(options)
.bind('typeahead:selected', function(obj, datum) {
element.tagsinput('add', datum.value);
element.tagsinput('input').typeahead('setQuery', '');
});
}
}
});
64 changes: 19 additions & 45 deletions examples/bootstrap3/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -297,19 +297,16 @@ <h3>Categorizing tags</h3>
<table class="table table-bordered table-condensed"><thead><tr><th>statement</th><th>returns</th></tr></thead><tbody><tr><td><code>$("input").val()</code></td><td><pre class="val prettyprint linenums"></pre></td></tr><tr><td><code>$("input").tagsinput('items')</code></td><td><pre class="items prettyprint linenums"></td></tr></tbody></table>
</div>

<!-- div id="angular" class="example example_angular" ng-app="AngularExample" ng-controller="CityTagsInputController">
<div id="angular" class="example example_angular" ng-app="AngularExample" ng-controller="Ctrl">
<h3>AngularJS support</h3>
<p>
Include <code>bootstrap-tagsinput-angular.js</code> and register the 'bootstrap-tagsinput' in your Angular JS application to use the bootstrap-tagsinput directive.
Include <code>bsTagsInput.js</code> and register the 'bsTagsInput' module in your Angular JS application to use the bs-tags-input directive.
</p>
<div class="bs-example">
<bootstrap-tagsinput
ng-model="cities"
typeahead-source="queryCities"
tagclass="getTagClass"
itemvalue="value"
itemtext="text">
</bootstrap-tagsinput>
<input type="text"
ng-model="tags"
bs-tags-input
bs-tags-typeahead="tagsTypeahead">
</div>
<div class="accordion">
<div class="accordion-group">
Expand All @@ -320,39 +317,18 @@ <h3>AngularJS support</h3>
</div>
<div id="example_angular" class="accordion-body collapse">
<div class="accordion-inner">
<pre class="prettyprint linenums">&lt;bootstrap-tagsinput
ng-model="cities"
typeahead-source="queryCities"
tagclass="getTagClass"
itemvalue="value"
itemtext="text"&gt;
&lt;/bootstrap-tagsinput&gt;
<pre class="prettyprint linenums">&lt;input type="text"
ng-model="tags"
bs-tags-input
bs-tags-typeahead="tagsTypeahead"&gt;

&lt;script&gt;
angular.module('AngularExample', ['bootstrap-tagsinput'])
.controller('CityTagsInputController',
function CityTagsInputController($scope) {
// Init with some cities
$scope.cities = [
{ "value": 1 , "text": "Amsterdam" , "continent": "Europe" },
{ "value": 4 , "text": "Washington" , "continent": "America" },
{ "value": 7 , "text": "Sydney" , "continent": "Australia" },
{ "value": 10, "text": "Beijing" , "continent": "Asia" },
{ "value": 13, "text": "Cairo" , "continent": "Africa" }
];
$scope.queryCities = function(query) {
return $http.get('cities.json');
};
$scope.getTagClass = function(city) {
switch (city.continent) {
case 'Europe' : return 'badge badge-info';
case 'America' : return 'label label-important';
case 'Australia': return 'badge badge-success';
case 'Africa' : return 'label label-inverse';
case 'Asia' : return 'badge badge-warning';
}
angular.module('AngularExample', ['bsTagsInput'])
.controller('Ctrl',
function Ctrl($scope) {
$scope.tags = ['Amsterdam', 'Washington'];
$scope.tagsTypeahead = {
local: ['Sydney', 'Beijing', 'Cairo']
};
}
);
Expand All @@ -366,13 +342,11 @@ <h3>AngularJS support</h3>
<tr><th>statement</th><th>returns</th></tr>
</thead>
<tbody>
<tr><td><code>$scope.cities</code></td><td><pre class="items prettyprint linenums">{{cities}}</td></tr>
<tr><td><code>$("select").val()</code></td><td><pre class="val prettyprint linenums"></pre></td></tr>
<tr><td><code>$("select").tagsinput('items')</code></td><td><pre class="items prettyprint linenums"></td></tr>
<tr><td><code>$scope.tags</code></td><td><pre class="items prettyprint linenums">{{tags}}</td></tr>
</tbody>
</table>
</div>
</section -->
</section>

<section id="options">
<div class="page-header">
Expand Down Expand Up @@ -561,7 +535,7 @@ <h2>Methods</h2>
<script src="assets/angular.min.js"></script>
<script src="assets/google-code-prettify/prettify.js"></script>
<script src="assets/bootstrap-tagsinput.js"></script>
<script src="assets/bootstrap-tagsinput-angular.js"></script>
<script src="assets/bsTagsInput.js"></script>
<script src="assets/typeahead.min.js"></script>
<script src="assets/hogan.js"></script>
<script src="assets/app_bs3.js"></script>
Expand Down
108 changes: 108 additions & 0 deletions src/bsTagsInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
angular.module('bsTagsInput', [])
/**
* @ngdoc directive
* @name bsTagsInput
* @restrict A
*
* @description
* Sets up an input field for tag inputs, using the bootstrap-tagsinput jQuery plugin.
*
* @element INPUT or SELECT
* @param {Object} options passed to the bootstrap-tagsinput plugin at initialization.
*
* @example
<doc:example>
<doc:source>
<script>
function Ctrl($scope) {
$scope.tags = ['Amsterdam', 'Washington'];
$scope.tagsTypeahead = {
local: ['Sydney', 'Beijing', 'Cairo']
}
}
</script>
<form ng-controller="Ctrl">
<input type="text" ng-model="tags" bs-tags-input bs-tags-typeahead="tagsTypeahead">
<pre>{{tags}}</pre>
</form>
</doc:source>
</doc:example>
*/
.directive('bsTagsInput', function() {
// reference to underscorejs/lodash difference method
var difference;
if (typeof(_) !== 'undefined') {
difference = _.difference;
} else {
// fallback to a naive implementation
difference = function(array, other) {
var results = [];
angular.forEach(array, function(value) {
if (other.indexOf(value) === -1) {
results.push(value);
}
});
return results;
};
}

return {
require: 'ngModel',
controller: function() {
},
link: function(scope, element, attrs, ngModelCtrl) {
// initialize tagsinput
var options = scope.$eval(attrs.bsTagsInput) || {};
element.tagsinput(options);

// handle changes from the underlying model
ngModelCtrl.$render = function() {
var oldVal = element.tagsinput('items'),
newVal = ngModelCtrl.$viewValue;
difference(oldVal, newVal).forEach(function(item) {
element.tagsinput('remove', item, true);
});
difference(newVal, oldVal).forEach(function(item) {
element.tagsinput('add', item, true);
});
};

// handle changes from the UI
element.on('change', function() {
var items = element.tagsinput('items');
ngModelCtrl.$setViewValue(items);
});

// handle cleanup
scope.$on('$destroy', function() {
element.tagsinput('destroy');
});
}
};
})
/**
* @ngdoc directive
* @name bsTagsTypeahead
* @restrict A
*
* @description
* Using typeahead.js, adds autocompletion support to a bsTagsInput field.
*
* @element INPUT or SELECT
* @param {Object} options passed to the typeahead.js plugin.
*/
.directive('bsTagsTypeahead', function() {
return {
require: 'bsTagsInput',
link: function(scope, element, attrs, bsTagsInputCtrl) {
// setup typeahead on the 'input' element
var options = scope.$eval(attrs.bsTagsTypeahead) || {};
element.tagsinput('input')
.typeahead(options)
.bind('typeahead:selected', function(obj, datum) {
element.tagsinput('add', datum.value);
element.tagsinput('input').typeahead('setQuery', '');
});
}
}
});

0 comments on commit 3c8ed65

Please sign in to comment.