Skip to content

Instantly share code, notes, and snippets.

@andyvr
Last active February 3, 2018 02:11
This is the Angular.js directive that converts html select boxes with Angularjs bindings into the Twitter Bootstrap dropboxes. See examples on jsfiddle: http://jsfiddle.net/M32pj/28/
angular.module('bsselect', [])
.directive('bsSelectbox', function ($parse) {
return {
restrict: 'A',
priority: 100,
transclude: true,
scope: {
themodel: '=ngModel',
thearray: '@ngOptions',
thechange: '&ngChange',
defaultval: '@bsSelectbox'
},
template:
'<div class="bs-selectbox btn-group">' +
'<button class="btn dropdown-toggle" data-toggle="dropdown" type="button">' +
'{{display}} ' +
'<span class="caret"></span>' +
'</button>' +
'<ul class="dropdown-menu">' +
'<li ng-show="defaultval">' +
'<a href="javascript:" ng-click="change(false)"> <span>{{defaultval}}</span> </a>' +
'</li>' +
'<li ng-show="defaultval" class="divider"></li>' +
'<li ng-repeat="itm in elements" ng-class="{active:itm.value==themodel}">' +
'<a href="javascript:" ng-click="change(itm)">' +
'<span>{{itm.label}}</span>' +
'</a>' +
'</li>' +
'</ul>' +
'<div style="display:none;" class="bs-selectbox-transclude" ng-transclude></div>' +
'</div>',
link: function (scope, element, attrs) {
scope.display = '--';
scope.elements = [];
attrs.$observe('bsSelectbox', function (value) {
if (value) scope.display = value;
});
attrs.$observe('ngOptions', function (value, element) {
if (angular.isDefined(value)) {
var match, loc = {};
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/;
if (match = value.match(NG_OPTIONS_REGEXP)) {
var displayFn = $parse(match[2] || match[1]),
valueName = match[4] || match[6],
valueFn = $parse(match[2] ? match[1] : valueName),
valuesFn = $parse(match[7]);
scope.$watch(function(){ return valuesFn(scope.$parent); }, function(newVal) {
var collection = newVal || [];
scope.elements = [];
angular.forEach(collection, function (value, key) {
loc[valueName] = collection[key];
scope.elements.push({
'label': displayFn(scope.$parent, loc),
'value': valueFn(scope.$parent, loc)
});
});
scope.setdefault();
});
}
}
});
scope.$watch('themodel', function (newval, oldval) {
scope.setdefault();
if(angular.isFunction(scope.thechange) && (newval != oldval)) {
scope.thechange();
}
});
scope.setdefault = function () {
angular.forEach(scope.elements, function (value, key) {
if (value.value == scope.themodel) scope.display = value.label;
});
}
scope.change = function (itm) {
if (!itm) {
scope.display = scope.defaultval;
scope.themodel = "";
} else {
scope.display = itm.label;
scope.themodel = itm.value;
}
}
var elements = element.find(".bs-selectbox-transclude").children();
if (angular.isObject(elements) && elements.length) {
angular.forEach(elements, function (value, key) {
scope.elements.push({
'label': value.innerText,
'value': value.value
});
});
scope.setdefault();
}
},
replace: true
};
});
@jonesmac
Copy link

Excellent Gist. Any change you can update it to work with angular 1.2.16? I found it referenced here - http://stackoverflow.com/questions/15090185/angularjs-bootstrap-dropdown-cant-do-ng-click-in-ng-repeat but when I change the fiddle to an updated version of angular, it breaks. It can't seem to populate the ul on line 19 with the updated values.

@Macadoshis
Copy link

Please upgrade your source code in ordre to $compile your template. It doesn't work with AngularJS 1.2+.
Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment