Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit 6c19de0

Browse files
committed
fix(dropdown): bind event listener on dropdown menu
- Bind keypress listener to dropdown menu for handling keyboard navigation
1 parent 35ced04 commit 6c19de0

File tree

2 files changed

+50
-38
lines changed

2 files changed

+50
-38
lines changed

src/dropdown/dropdown.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
1111
this.open = function(dropdownScope, element) {
1212
if (!openScope) {
1313
$document.on('click', closeDropdown);
14-
element.on('keydown', keybindFilter);
1514
}
1615

1716
if (openScope && openScope !== dropdownScope) {
@@ -25,7 +24,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
2524
if (openScope === dropdownScope) {
2625
openScope = null;
2726
$document.off('click', closeDropdown);
28-
element.off('keydown', keybindFilter);
27+
dropdownScope.getDropdownElement().off('keydown', this.keybindFilter);
2928
}
3029
};
3130

@@ -57,7 +56,7 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
5756
}
5857
};
5958

60-
var keybindFilter = function(evt) {
59+
this.keybindFilter = function(evt) {
6160
if (evt.which === 27) {
6261
evt.stopPropagation();
6362
openScope.focusToggleElement();
@@ -248,13 +247,17 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
248247
var newEl = dropdownElement;
249248
self.dropdownMenu.replaceWith(newEl);
250249
self.dropdownMenu = newEl;
250+
self.dropdownMenu.on('keydown', uibDropdownService.keybindFilter);
251251
});
252252
});
253+
} else {
254+
scope.getDropdownElement().on('keydown', uibDropdownService.keybindFilter);
253255
}
254256

255257
scope.focusToggleElement();
256258
uibDropdownService.open(scope, $element);
257259
} else {
260+
uibDropdownService.close(scope, $element);
258261
if (self.dropdownMenuTemplateUrl) {
259262
if (templateScope) {
260263
templateScope.$destroy();
@@ -264,7 +267,6 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
264267
self.dropdownMenu = newEl;
265268
}
266269

267-
uibDropdownService.close(scope, $element);
268270
self.selectedOption = null;
269271
}
270272

src/dropdown/test/dropdown.spec.js

+44-34
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('uib-dropdown', function() {
3535

3636
describe('basic', function() {
3737
function dropdown() {
38-
return $compile('<li uib-dropdown><a href uib-dropdown-toggle></a><ul><li><a href>Hello</a></li></ul></li>')($rootScope);
38+
return $compile('<li uib-dropdown><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li></ul></li>')($rootScope);
3939
}
4040

4141
beforeEach(function() {
@@ -69,9 +69,10 @@ describe('uib-dropdown', function() {
6969
});
7070

7171
it('should close on escape key & focus toggle element', function() {
72+
var dropdownMenu = element.find('[uib-dropdown-menu]');
7273
$document.find('body').append(element);
7374
clickDropdownToggle();
74-
var event = triggerKeyDown(element, 27);
75+
var event = triggerKeyDown(dropdownMenu, 27);
7576
expect(element).not.toHaveClass(dropdownConfig.openClass);
7677
expect(element.find('a')).toHaveFocus();
7778
expect(event.stopPropagation).toHaveBeenCalled();
@@ -108,7 +109,7 @@ describe('uib-dropdown', function() {
108109
});
109110

110111
it('should not toggle if the element has `disabled` class', function() {
111-
var elm = $compile('<li uib-dropdown><a class="disabled" uib-dropdown-toggle></a><ul><li>Hello</li></ul></li>')($rootScope);
112+
var elm = $compile('<li uib-dropdown><a class="disabled" uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
112113
clickDropdownToggle( elm );
113114
expect(elm).not.toHaveClass(dropdownConfig.openClass);
114115
});
@@ -121,7 +122,7 @@ describe('uib-dropdown', function() {
121122

122123
it('should not toggle if the element has `ng-disabled` as true', function() {
123124
$rootScope.isdisabled = true;
124-
var elm = $compile('<li uib-dropdown><div ng-disabled="isdisabled" uib-dropdown-toggle></div><ul><li>Hello</li></ul></li>')($rootScope);
125+
var elm = $compile('<li uib-dropdown><div ng-disabled="isdisabled" uib-dropdown-toggle></div><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
125126
$rootScope.$digest();
126127
elm.find('div').click();
127128
expect(elm).not.toHaveClass(dropdownConfig.openClass);
@@ -134,7 +135,7 @@ describe('uib-dropdown', function() {
134135

135136
it('should unbind events on scope destroy', function() {
136137
var $scope = $rootScope.$new();
137-
var elm = $compile('<li uib-dropdown><button ng-disabled="isdisabled" uib-dropdown-toggle></button><ul><li>Hello</li></ul></li>')($scope);
138+
var elm = $compile('<li uib-dropdown><button ng-disabled="isdisabled" uib-dropdown-toggle></button><ul uib-dropdown-menu><li>Hello</li></ul></li>')($scope);
138139
$scope.$digest();
139140

140141
var buttonEl = elm.find('button');
@@ -306,7 +307,7 @@ describe('uib-dropdown', function() {
306307
describe('with uib-dropdown-toggle', function() {
307308
beforeEach(function() {
308309
$rootScope.isopen = true;
309-
element = $compile('<li uib-dropdown is-open="isopen"><a href uib-dropdown-toggle></a><ul><li>Hello</li></ul></li>')($rootScope);
310+
element = $compile('<li uib-dropdown is-open="isopen"><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
310311
$rootScope.$digest();
311312
});
312313

@@ -340,7 +341,7 @@ describe('uib-dropdown', function() {
340341
describe('without uib-dropdown-toggle', function() {
341342
beforeEach(function() {
342343
$rootScope.isopen = true;
343-
element = $compile('<li uib-dropdown is-open="isopen"><ul><li>Hello</li></ul></li>')($rootScope);
344+
element = $compile('<li uib-dropdown is-open="isopen"><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
344345
$rootScope.$digest();
345346
});
346347

@@ -361,7 +362,7 @@ describe('uib-dropdown', function() {
361362
beforeEach(function() {
362363
$rootScope.toggleHandler = jasmine.createSpy('toggleHandler');
363364
$rootScope.isopen = false;
364-
element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)" is-open="isopen"><a uib-dropdown-toggle></a><ul><li>Hello</li></ul></li>')($rootScope);
365+
element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)" is-open="isopen"><a uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
365366
$rootScope.$digest();
366367
});
367368

@@ -388,7 +389,7 @@ describe('uib-dropdown', function() {
388389
beforeEach(function() {
389390
$rootScope.toggleHandler = jasmine.createSpy('toggleHandler');
390391
$rootScope.isopen = true;
391-
element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)" is-open="isopen"><a uib-dropdown-toggle></a><ul><li>Hello</li></ul></li>')($rootScope);
392+
element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)" is-open="isopen"><a uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
392393
$rootScope.$digest();
393394
});
394395

@@ -416,7 +417,7 @@ describe('uib-dropdown', function() {
416417
describe('without is-open', function() {
417418
beforeEach(function() {
418419
$rootScope.toggleHandler = jasmine.createSpy('toggleHandler');
419-
element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)"><a uib-dropdown-toggle></a><ul><li>Hello</li></ul></li>')($rootScope);
420+
element = $compile('<li uib-dropdown on-toggle="toggleHandler(open)"><a uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
420421
$rootScope.$digest();
421422
});
422423

@@ -444,7 +445,7 @@ describe('uib-dropdown', function() {
444445
function dropdown(autoClose) {
445446
return $compile('<li uib-dropdown ' +
446447
(autoClose === undefined ? '' : 'auto-close="' + autoClose + '"') +
447-
'><a href uib-dropdown-toggle></a><ul><li><a href>Hello</a></li></ul></li>')($rootScope);
448+
'><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li></ul></li>')($rootScope);
448449
}
449450

450451
describe('always', function() {
@@ -476,7 +477,7 @@ describe('uib-dropdown', function() {
476477

477478
it('control with is-open', function() {
478479
$rootScope.isopen = true;
479-
element = $compile('<li uib-dropdown is-open="isopen" auto-close="disabled"><a href uib-dropdown-toggle></a><ul><li>Hello</li></ul></li>')($rootScope);
480+
element = $compile('<li uib-dropdown is-open="isopen" auto-close="disabled"><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li>Hello</li></ul></li>')($rootScope);
480481
$rootScope.$digest();
481482

482483
expect(element).toHaveClass(dropdownConfig.openClass);
@@ -499,9 +500,10 @@ describe('uib-dropdown', function() {
499500

500501
it('should close anyway if esc is pressed', function() {
501502
element = dropdown('disabled');
503+
var dropdownMenu = element.find('[uib-dropdown-menu]');
502504
$document.find('body').append(element);
503505
clickDropdownToggle();
504-
triggerKeyDown(element, 27);
506+
triggerKeyDown(dropdownMenu, 27);
505507
expect(element).not.toHaveClass(dropdownConfig.openClass);
506508
expect(element.find('a')).toHaveFocus();
507509
});
@@ -546,66 +548,72 @@ describe('uib-dropdown', function() {
546548

547549
describe('using keyboard-nav', function() {
548550
function dropdown() {
549-
return $compile('<li uib-dropdown keyboard-nav><a href uib-dropdown-toggle></a><ul><li><a href>Hello</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope);
551+
return $compile('<li uib-dropdown keyboard-nav><a href uib-dropdown-toggle></a><ul uib-dropdown-menu><li><a href>Hello</a></li><li><a href>Hello Again</a></li></ul></li>')($rootScope);
550552
}
551553
beforeEach(function() {
552554
element = dropdown();
553555
});
554556

555557
it('should focus first list element when down arrow pressed', function() {
558+
var dropdownMenu = element.find('[uib-dropdown-menu]');
556559
$document.find('body').append(element);
557560
clickDropdownToggle();
558-
triggerKeyDown(element, 40);
561+
triggerKeyDown(dropdownMenu, 40);
559562

560563
expect(element).toHaveClass(dropdownConfig.openClass);
561564
var optionEl = element.find('ul').eq(0).find('a').eq(0);
562565
expect(optionEl).toHaveFocus();
563566
});
564567

565568
it('should not focus first list element when down arrow pressed if closed', function() {
569+
var dropdownMenu = element.find('[uib-dropdown-menu]');
566570
$document.find('body').append(element);
567-
triggerKeyDown(element, 40);
571+
triggerKeyDown(dropdownMenu, 40);
568572

569573
expect(element).not.toHaveClass(dropdownConfig.openClass);
570574
var focusEl = element.find('ul').eq(0).find('a').eq(0);
571575
expect(focusEl).not.toHaveFocus();
572576
});
573577

574578
it('should focus second list element when down arrow pressed twice', function() {
579+
var dropdownMenu = element.find('[uib-dropdown-menu]');
575580
$document.find('body').append(element);
576581
clickDropdownToggle();
577-
triggerKeyDown(element, 40);
578-
triggerKeyDown(element, 40);
582+
triggerKeyDown(dropdownMenu, 40);
583+
triggerKeyDown(dropdownMenu, 40);
579584

580585
expect(element).toHaveClass(dropdownConfig.openClass);
581586
var focusEl = element.find('ul').eq(0).find('a').eq(1);
582587
expect(focusEl).toHaveFocus();
583588
});
584589

585590
it('should not focus first list element when up arrow pressed after dropdown toggled', function() {
591+
var dropdownMenu = element.find('[uib-dropdown-menu]');
586592
$document.find('body').append(element);
587593
clickDropdownToggle();
588594
expect(element).toHaveClass(dropdownConfig.openClass);
589595

590-
triggerKeyDown(element, 38);
596+
triggerKeyDown(dropdownMenu, 38);
591597
var focusEl = element.find('ul').eq(0).find('a').eq(0);
592598
expect(focusEl).not.toHaveFocus();
593599
});
594600

595601
it('should focus last list element when up arrow pressed after dropdown toggled', function() {
602+
var dropdownMenu = element.find('[uib-dropdown-menu]');
596603
$document.find('body').append(element);
597604
clickDropdownToggle();
598-
triggerKeyDown(element, 38);
605+
triggerKeyDown(dropdownMenu, 38);
599606

600607
expect(element).toHaveClass(dropdownConfig.openClass);
601608
var focusEl = element.find('ul').eq(0).find('a').eq(1);
602609
expect(focusEl).toHaveFocus();
603610
});
604611

605612
it('should not change focus when other keys are pressed', function() {
613+
var dropdownMenu = element.find('[uib-dropdown-menu]');
606614
$document.find('body').append(element);
607615
clickDropdownToggle();
608-
triggerKeyDown(element, 37);
616+
triggerKeyDown(dropdownMenu, 37);
609617

610618
expect(element).toHaveClass(dropdownConfig.openClass);
611619
var focusEl = element.find('ul').eq(0).find('a');
@@ -614,23 +622,25 @@ describe('uib-dropdown', function() {
614622
});
615623

616624
it('should focus first list element when down arrow pressed 2x and up pressed 1x', function() {
625+
var dropdownMenu = element.find('[uib-dropdown-menu]');
617626
$document.find('body').append(element);
618627
clickDropdownToggle();
619-
triggerKeyDown(element, 40);
620-
triggerKeyDown(element, 40);
628+
triggerKeyDown(dropdownMenu, 40);
629+
triggerKeyDown(dropdownMenu, 40);
621630

622-
triggerKeyDown(element, 38);
631+
triggerKeyDown(dropdownMenu, 38);
623632

624633
expect(element).toHaveClass(dropdownConfig.openClass);
625634
var focusEl = element.find('ul').eq(0).find('a').eq(0);
626635
expect(focusEl).toHaveFocus();
627636
});
628637

629638
it('should stay focused on final list element if down pressed at list end', function() {
639+
var dropdownMenu = element.find('[uib-dropdown-menu]');
630640
$document.find('body').append(element);
631641
clickDropdownToggle();
632-
triggerKeyDown(element, 40);
633-
triggerKeyDown(element, 40);
642+
triggerKeyDown(dropdownMenu, 40);
643+
triggerKeyDown(dropdownMenu, 40);
634644

635645
expect(element).toHaveClass(dropdownConfig.openClass);
636646
var focusEl = element.find('ul').eq(0).find('a').eq(1);
@@ -642,16 +652,17 @@ describe('uib-dropdown', function() {
642652

643653
it('should close if esc is pressed while focused', function() {
644654
element = dropdown('disabled');
655+
var dropdownMenu = element.find('[uib-dropdown-menu]');
645656
$document.find('body').append(element);
646657
clickDropdownToggle();
647658

648-
triggerKeyDown(element, 40);
659+
triggerKeyDown(dropdownMenu, 40);
649660

650661
expect(element).toHaveClass(dropdownConfig.openClass);
651662
var focusEl = element.find('ul').eq(0).find('a').eq(0);
652663
expect(focusEl).toHaveFocus();
653664

654-
triggerKeyDown(element, 27);
665+
triggerKeyDown(dropdownMenu, 27);
655666
expect(element).not.toHaveClass(dropdownConfig.openClass);
656667
});
657668

@@ -667,22 +678,21 @@ describe('uib-dropdown', function() {
667678
it('should focus first list element when down arrow pressed', function() {
668679
clickDropdownToggle();
669680

670-
triggerKeyDown(element, 40);
671-
672681
var dropdownMenu = $document.find('#dropdown-menu');
673682

683+
triggerKeyDown(dropdownMenu, 40);
684+
674685
expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass);
675686
var focusEl = $document.find('ul').eq(0).find('a');
676687
expect(focusEl).toHaveFocus();
677688
});
678689

679690
it('should focus second list element when down arrow pressed twice', function() {
680691
clickDropdownToggle();
681-
triggerKeyDown(element, 40);
682-
triggerKeyDown(element, 40);
683-
triggerKeyDown(element, 40);
684-
685692
var dropdownMenu = $document.find('#dropdown-menu');
693+
triggerKeyDown(dropdownMenu, 40);
694+
triggerKeyDown(dropdownMenu, 40);
695+
triggerKeyDown(dropdownMenu, 40);
686696

687697
expect(dropdownMenu.parent()).toHaveClass(dropdownConfig.appendToOpenClass);
688698
var elem1 = $document.find('ul');

0 commit comments

Comments
 (0)