diff --git a/build/angular-bootstrap-select.js b/build/angular-bootstrap-select.js
index 4249982..aa72d9f 100644
--- a/build/angular-bootstrap-select.js
+++ b/build/angular-bootstrap-select.js
@@ -1,59 +1,229 @@
-// supply open and close without load bootstrap.js
+'use strict';
+
+/**
+ * @ngdoc module
+ * @name angular-bootstrap-select.extra
+ * @description
+ * Angular bootstrap-select extra.
+ */
+
angular.module('angular-bootstrap-select.extra', [])
- .directive('toggle', function () {
- return {
- restrict: 'A',
- link: function (scope, element, attrs) {
- // prevent directive from attaching itself to everything that defines a toggle attribute
- if (!element.hasClass('selectpicker')) {
- return;
- }
-
- var target = element.parent();
- var toggleFn = function () {
- target.toggleClass('open');
- };
- var hideFn = function () {
- target.removeClass('open');
- };
-
- element.on('click', toggleFn);
- element.next().on('click', hideFn);
-
- scope.$on('$destroy', function () {
- element.off('click', toggleFn);
- element.next().off('click', hideFn);
+ .directive('dropdownToggle', [dropdownToggleDirective])
+ .directive('dropdownClose', [dropdownCloseDirective]);
+
+/**
+ * @ngdoc directive
+ * @name dropdownToggle
+ * @restrict ACE
+ *
+ * @description
+ * This extra directive provide dropdown toggle specifically to bootstrap-select without loading bootstrap.js.
+ *
+ * @usage
+ * ```html
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * ```
+ */
+
+function dropdownToggleDirective() {
+ return {
+ restrict: 'ACE',
+ priority: 101,
+ link: function (scope, element, attrs) {
+ var toggleFn = function (e) {
+ var parent = angular.element(this).parent();
+
+ angular.element('.bootstrap-select.open', element)
+ .not(parent)
+ .removeClass('open');
+
+ parent.toggleClass('open');
+ };
+
+ element.on('click.bootstrapSelect', '.dropdown-toggle', toggleFn);
+
+ scope.$on('$destroy', function () {
+ element.off('.bootstrapSelect');
+ });
+ }
+ };
+}
+
+/**
+ * @ngdoc directive
+ * @name dropdownClear
+ * @restrict ACE
+ *
+ * @description
+ * This extra directive provide the closing of ALL open dropdowns clicking away
+ *
+ * @usage
+ * ```html
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * ```
+ */
+
+function dropdownCloseDirective() {
+ return {
+ restrict: 'ACE',
+ priority: 101,
+ link: function (scope, element, attrs) {
+ var hideFn = function (e) {
+ var parent = e.target.tagName !== 'A' && angular.element(e.target).parents('.bootstrap-select');
+
+ angular.element('.bootstrap-select.open', element)
+ .not(parent)
+ .removeClass('open');
+ };
+
+ angular.element(document).on('click.bootstrapSelect', hideFn);
+
+ scope.$on('$destroy', function () {
+ angular.element(document).off('.bootstrapSelect');
+ });
+ }
+ };
+}
+
+/**
+ * @ngdoc module
+ * @name angular-bootstrap-select
+ * @description
+ * Angular bootstrap-select.
+ */
+
+angular.module('angular-bootstrap-select', [])
+ .directive('selectpicker', ['$parse', '$timeout', selectpickerDirective]);
+
+/**
+ * @ngdoc directive
+ * @name selectpicker
+ * @restrict A
+ *
+ * @param {object} selectpicker Directive attribute to configure bootstrap-select, full configurable params can be found in [bootstrap-select docs](http://silviomoreto.github.io/bootstrap-select/).
+ * @param {string} ngModel Assignable angular expression to data-bind to.
+ *
+ * @description
+ * The selectpicker directive is used to wrap bootstrap-select.
+ *
+ * @usage
+ * ```html
+ *
+ *
+ *
+ * ```
+ */
+
+function selectpickerDirective($parse, $timeout) {
+ return {
+ restrict: 'A',
+ priority: 1000,
+ link: function (scope, element, attrs) {
+ function refresh(newVal) {
+ scope.$applyAsync(function () {
+ if (attrs.ngOptions && /track by/.test(attrs.ngOptions)) element.val(newVal);
+ element.selectpicker('refresh');
+
+ element.data('selectpicker').$newElement.removeClass(function (i, c){
+ return (c.match(/ng-[^\s]+/g) || []).join(' ');
+ });
});
}
- };
- });
-angular.module('angular-bootstrap-select', [])
- .directive('selectpicker', ['$parse', function ($parse) {
- return {
- restrict: 'A',
- require: '?ngModel',
- priority: 10,
- compile: function (tElement, tAttrs, transclude) {
- tElement.selectpicker($parse(tAttrs.selectpicker)());
- tElement.selectpicker('refresh');
- return function (scope, element, attrs, ngModel) {
- if (!ngModel) return;
-
- scope.$watch(attrs.ngModel, function (newVal, oldVal) {
- scope.$evalAsync(function () {
- if (!attrs.ngOptions || /track by/.test(attrs.ngOptions)) element.val(newVal);
- element.selectpicker('refresh');
- });
+ attrs.$observe('spTheme', function (val) {
+ $timeout(function () {
+ element.data('selectpicker').$button.removeClass(function (i, c) {
+ return (c.match(/(^|\s)?btn-\S+/g) || []).join(' ');
});
+ element.selectpicker('setStyle', val);
+ });
+ });
+
+ $timeout(function () {
+ element.selectpicker($parse(attrs.selectpicker)());
+ element.selectpicker('refresh');
+ });
- ngModel.$render = function () {
- scope.$evalAsync(function () {
- element.selectpicker('refresh');
- });
- }
- };
+ if (attrs.ngModel) {
+ scope.$watch(attrs.ngModel, refresh, true);
}
-
- };
- }]);
+
+ if (attrs.ngDisabled) {
+ scope.$watch(attrs.ngDisabled, refresh, true);
+ }
+
+ if (attrs.ngOptions) {
+ var watch = attrs.ngOptions.match(/in ([A-z0-9]+)$/);
+ if (watch) {
+ scope.$watch(watch[1], refresh, true);
+ }
+ }
+
+ scope.$on('$destroy', function () {
+ $timeout(function () {
+ element.selectpicker('destroy');
+ });
+ });
+ }
+ };
+}
diff --git a/build/angular-bootstrap-select.min.js b/build/angular-bootstrap-select.min.js
index 8b54960..30cf066 100644
--- a/build/angular-bootstrap-select.min.js
+++ b/build/angular-bootstrap-select.min.js
@@ -1 +1 @@
-angular.module("angular-bootstrap-select.extra",[]).directive("toggle",function(){return{restrict:"A",link:function(a,b){if(b.hasClass("selectpicker")){var c=b.parent(),d=function(){c.toggleClass("open")},e=function(){c.removeClass("open")};b.on("click",d),b.next().on("click",e),a.$on("$destroy",function(){b.off("click",d),b.next().off("click",e)})}}}}),angular.module("angular-bootstrap-select",[]).directive("selectpicker",["$parse",function(a){return{restrict:"A",require:"?ngModel",priority:10,compile:function(b,c){return b.selectpicker(a(c.selectpicker)()),b.selectpicker("refresh"),function(a,b,c,d){d&&(a.$watch(c.ngModel,function(d){a.$evalAsync(function(){(!c.ngOptions||/track by/.test(c.ngOptions))&&b.val(d),b.selectpicker("refresh")})}),d.$render=function(){a.$evalAsync(function(){b.selectpicker("refresh")})})}}}}]);
\ No newline at end of file
+"use strict";function dropdownToggleDirective(){return{restrict:"ACE",priority:101,link:function(a,b,c){var d=function(a){var c=angular.element(this).parent();angular.element(".bootstrap-select.open",b).not(c).removeClass("open"),c.toggleClass("open")};b.on("click.bootstrapSelect",".dropdown-toggle",d),a.$on("$destroy",function(){b.off(".bootstrapSelect")})}}}function dropdownCloseDirective(){return{restrict:"ACE",priority:101,link:function(a,b,c){var d=function(a){var c="A"!==a.target.tagName&&angular.element(a.target).parents(".bootstrap-select");angular.element(".bootstrap-select.open",b).not(c).removeClass("open")};angular.element(document).on("click.bootstrapSelect",d),a.$on("$destroy",function(){angular.element(document).off(".bootstrapSelect")})}}}function selectpickerDirective(a,b){return{restrict:"A",priority:1e3,link:function(c,d,e){function f(a){c.$applyAsync(function(){e.ngOptions&&/track by/.test(e.ngOptions)&&d.val(a),d.selectpicker("refresh"),d.data("selectpicker").$newElement.removeClass(function(a,b){return(b.match(/ng-[^\s]+/g)||[]).join(" ")})})}if(e.$observe("spTheme",function(a){b(function(){d.data("selectpicker").$button.removeClass(function(a,b){return(b.match(/(^|\s)?btn-\S+/g)||[]).join(" ")}),d.selectpicker("setStyle",a)})}),b(function(){d.selectpicker(a(e.selectpicker)()),d.selectpicker("refresh")}),e.ngModel&&c.$watch(e.ngModel,f,!0),e.ngDisabled&&c.$watch(e.ngDisabled,f,!0),e.ngOptions){var g=e.ngOptions.match(/in ([A-z0-9]+)$/);g&&c.$watch(g[1],f,!0)}c.$on("$destroy",function(){b(function(){d.selectpicker("destroy")})})}}}angular.module("angular-bootstrap-select.extra",[]).directive("dropdownToggle",[dropdownToggleDirective]).directive("dropdownClose",[dropdownCloseDirective]),angular.module("angular-bootstrap-select",[]).directive("selectpicker",["$parse","$timeout",selectpickerDirective]);
\ No newline at end of file
diff --git a/src/angular-bootstrap-select.js b/src/angular-bootstrap-select.js
index 67d80aa..aa72d9f 100644
--- a/src/angular-bootstrap-select.js
+++ b/src/angular-bootstrap-select.js
@@ -183,6 +183,10 @@ function selectpickerDirective($parse, $timeout) {
scope.$applyAsync(function () {
if (attrs.ngOptions && /track by/.test(attrs.ngOptions)) element.val(newVal);
element.selectpicker('refresh');
+
+ element.data('selectpicker').$newElement.removeClass(function (i, c){
+ return (c.match(/ng-[^\s]+/g) || []).join(' ');
+ });
});
}
@@ -208,6 +212,13 @@ function selectpickerDirective($parse, $timeout) {
scope.$watch(attrs.ngDisabled, refresh, true);
}
+ if (attrs.ngOptions) {
+ var watch = attrs.ngOptions.match(/in ([A-z0-9]+)$/);
+ if (watch) {
+ scope.$watch(watch[1], refresh, true);
+ }
+ }
+
scope.$on('$destroy', function () {
$timeout(function () {
element.selectpicker('destroy');