Skip to content

Commit ebf395e

Browse files
committed
feat(select): add support for bootstrap-select
1 parent 00a084e commit ebf395e

File tree

6 files changed

+719
-1
lines changed

6 files changed

+719
-1
lines changed

component.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"jquery": ">= 1.8.0",
1414
"bootstrap": ">= 2.2.0",
1515
"bootstrap-datepicker": ">= 1.0.0",
16-
"bootstrap-timepicker": ">= 0.2.2"
16+
"bootstrap-timepicker": ">= 0.2.2",
17+
"bootstrap-select": "latest"
1718
}
1819
}

src/directives/select.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
angular.module('$strap.directives')
3+
4+
.directive('bsSelect', function() {
5+
'use strict';
6+
7+
return {
8+
9+
scope: true,
10+
11+
link: function (scope, element, attrs) {
12+
13+
var previousClasses = element.attr('class');
14+
15+
var syncClasses = function () {
16+
var currentClasses = element.attr('class');
17+
element.next().removeClass(previousClasses).addClass(currentClasses).removeClass('ng-scope');
18+
previousClasses = element.attr('class');
19+
};
20+
21+
// Watch for changes to the length of our select element
22+
scope.$watch(function () {
23+
return element[0].length;
24+
}, function () {
25+
element.selectpicker('render');
26+
});
27+
28+
// Watch for changes to the model value
29+
scope.$watch(attrs.ngModel, function () {
30+
element.selectpicker('render');
31+
syncClasses();
32+
});
33+
34+
}
35+
36+
};
37+
38+
});

test/testacular.conf.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ files = [
1818
'vendor/bootstrap-datepicker.js',
1919
//'vendor/bootstrap-datepicker.fr.js',
2020
'vendor/bootstrap-timepicker.js',
21+
'vendor/bootstrap-select.js',
2122
'src/common.js',
2223
'src/directives/*.js',
2324
'test/unit/directives/*Spec.js'

test/unit/directives/selectSpec.js

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
'use strict';
2+
3+
describe('select directive', function () {
4+
5+
var fixture;
6+
var element;
7+
var currentScope;
8+
var bootstrapSelect;
9+
var menu;
10+
11+
beforeEach(module('$strap.directives'));
12+
13+
beforeEach(function () {
14+
var body = angular.element('body');
15+
fixture = angular.element('<div></div>');
16+
fixture.appendTo(body);
17+
});
18+
19+
afterEach(function () {
20+
fixture.remove();
21+
});
22+
23+
beforeEach(inject(function ($compile, $rootScope) {
24+
25+
element = angular.element('<select bs-select ng-model="model.item" ng-options="i.id as i.name for i in items"></select>');
26+
element.appendTo(fixture);
27+
28+
currentScope = $rootScope;
29+
30+
$rootScope.model = {
31+
item: 2
32+
};
33+
34+
$rootScope.items = [
35+
{
36+
id: 1,
37+
name: 'item 1'
38+
},
39+
{
40+
id: 2,
41+
name: 'item 2'
42+
}
43+
];
44+
45+
$compile(element)($rootScope, false);
46+
$rootScope.$digest();
47+
48+
bootstrapSelect = element.siblings('.bootstrap-select');
49+
menu = bootstrapSelect.find('ul[role=menu]');
50+
51+
}));
52+
53+
it('initialises bootstrap select on the element', function () {
54+
expect(bootstrapSelect.length).toBe(1);
55+
});
56+
57+
it('adds every item to the bootstrap select menu', function () {
58+
expect(menu.children().length).toBe(2);
59+
});
60+
61+
it('updates the bootstrap select menu when items are changed', function () {
62+
63+
currentScope.items.push({
64+
id: 3,
65+
name: 'item 3'
66+
});
67+
currentScope.$apply();
68+
69+
expect(menu.children().length).toBe(3);
70+
});
71+
72+
it('selects the correct item by default', function () {
73+
expect(menu.find('.selected').text()).toBe('item 2');
74+
});
75+
76+
it('updates the scope when a new item is selected', function () {
77+
78+
menu.find('li a').first().click();
79+
80+
expect(currentScope.model.item).toBe(1);
81+
});
82+
83+
it('updates bootstrap select when the model changes', function () {
84+
85+
currentScope.model.item = 1;
86+
currentScope.$apply();
87+
88+
expect(menu.find('.selected').text()).toBe('item 1');
89+
});
90+
91+
it('does not add ng-scope class to bootstrap select element', function () {
92+
expect(bootstrapSelect.hasClass('ng-scope')).toBe(false);
93+
});
94+
95+
it('adds new classes from original element when the model changes', function () {
96+
97+
element.addClass('dummy');
98+
99+
currentScope.model.item = 1;
100+
currentScope.$apply();
101+
102+
expect(bootstrapSelect.hasClass('dummy')).toBe(true);
103+
});
104+
105+
it('syncs classes removed from original element when the model changes', function () {
106+
107+
element.addClass('dummy');
108+
109+
currentScope.model.item = 1;
110+
currentScope.$apply();
111+
112+
element.removeClass('dummy');
113+
114+
currentScope.model.item = 2;
115+
currentScope.$apply();
116+
117+
expect(bootstrapSelect.hasClass('dummy')).toBe(false);
118+
});
119+
120+
});

vendor/bootstrap-select.css

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
.clearfix:after {
2+
visibility: hidden;
3+
display: block;
4+
font-size: 0;
5+
content: " ";
6+
clear: both;
7+
height: 0;
8+
}
9+
10+
.bootstrap-select.btn-group, .bootstrap-select.btn-group[class*="span"] {
11+
float:none;
12+
display: inline-block;
13+
margin-bottom: 10px;
14+
margin-left:0;
15+
}
16+
17+
.input-append .bootstrap-select.btn-group {
18+
margin-left: -1px;
19+
}
20+
21+
.input-prepend .bootstrap-select.btn-group {
22+
margin-right: -1px;
23+
}
24+
25+
.bootstrap-select {
26+
width: 220px;
27+
}
28+
29+
.bootstrap-select .btn {
30+
width: 100%;
31+
}
32+
33+
.bootstrap-select .btn:focus {
34+
outline: thin dotted #333333 !important;
35+
outline: 5px auto -webkit-focus-ring-color !important;
36+
outline-offset: -2px;
37+
}
38+
39+
.bootstrap-select.btn-group .btn .filter-option {
40+
overflow:hidden;
41+
position:absolute;
42+
left:12px;
43+
right:25px;
44+
text-align:left;
45+
}
46+
47+
.bootstrap-select.btn-group .btn .caret {
48+
position:absolute;
49+
right:12px;
50+
}
51+
52+
.bootstrap-select.btn-group > .disabled, .bootstrap-select.btn-group .dropdown-menu li.disabled > a {
53+
cursor: not-allowed;
54+
}
55+
56+
.bootstrap-select.btn-group[class*="span"] .btn {
57+
width:100%;
58+
}
59+
60+
.bootstrap-select.btn-group .dropdown-menu {
61+
min-width:100%;
62+
-moz-box-sizing:border-box;
63+
-webkit-box-sizing:border-box;
64+
box-sizing:border-box;
65+
}
66+
67+
.bootstrap-select.btn-group .dropdown-menu dt {
68+
display:block;
69+
padding:3px 20px;
70+
cursor:default;
71+
}
72+
73+
.bootstrap-select.btn-group .div-contain {
74+
overflow:hidden;
75+
}
76+
77+
.bootstrap-select.btn-group .dropdown-menu li > a.opt {
78+
padding-left:35px;
79+
}
80+
81+
.bootstrap-select.btn-group .dropdown-menu li > a {
82+
min-height:20px;
83+
}
84+
85+
bootstrap-select.btn-group .dropdown-menu li > a {
86+
min-height:20px;
87+
}
88+
89+
.bootstrap-select.btn-group .dropdown-menu li small {
90+
padding-left:0.5em;
91+
}
92+
93+
.bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:hover small {
94+
color: #64b1d8;
95+
color:rgba(255,255,255,0.4);
96+
}
97+
98+
.bootstrap-select.btn-group .dropdown-menu li > dt small {
99+
font-weight:normal;
100+
}
101+
102+
103+
.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark {
104+
display:inline-block;
105+
position: absolute;
106+
right: 20px;
107+
}
108+
109+
.bootstrap-select.btn-group .dropdown-menu li a i.check-mark {
110+
display: none;
111+
}
112+
113+
.bootstrap-select.btn-group.show-tick .dropdown-menu li a .pull-left {
114+
margin-right: 34px;
115+
}
116+
117+
.bootstrap-select.btn-group .dropdown-menu li small {
118+
padding-left:0.5em;
119+
}
120+
121+
.bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:hover small, .bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:focus small {
122+
color: #64b1d8;
123+
color:rgba(255,255,255,0.4);
124+
}
125+
126+
.bootstrap-select.btn-group .dropdown-menu li > dt small {
127+
font-weight:normal;
128+
}
129+
130+
131+
.bootstrap-select.btn-group.show-menu-arrow .dropdown-menu {
132+
overflow-y:visible !important;
133+
}
134+
135+
.bootstrap-select.btn-group.show-menu-arrow .dropdown-menu::after {
136+
position: absolute;
137+
top: -6px;
138+
left: 10px;
139+
display: inline-block;
140+
border-right: 6px solid transparent;
141+
border-bottom: 6px solid white;
142+
border-left: 6px solid transparent;
143+
content: '';
144+
}
145+
146+
.bootstrap-select.btn-group.show-menu-arrow .dropdown-menu::before {
147+
position: absolute;
148+
top: -7px;
149+
left: 9px;
150+
display: inline-block;
151+
border-right: 7px solid transparent;
152+
border-bottom: 7px solid #CCC;
153+
border-left: 7px solid transparent;
154+
border-bottom-color: rgba(0, 0, 0, 0.2);
155+
content: '';
156+
}

0 commit comments

Comments
 (0)