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');