Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 5228f23

Browse files
marosoftSplaktar
authored andcommitted
fix(autocomplete): loop options list when moving past first/last option with arrow keys
allow the user cycling through the options list Fixes #11766
1 parent 6dc3b02 commit 5228f23

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

src/components/autocomplete/autocomplete.spec.js

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,106 @@ describe('<md-autocomplete>', function() {
19701970
element.remove();
19711971
});
19721972

1973+
it('should move to the last item when up arrow is pressed when on the first item', function() {
1974+
var template =
1975+
'<md-autocomplete' +
1976+
' md-selected-item="selectedItem"' +
1977+
' md-search-text="searchText"' +
1978+
' md-items="item in match(searchText)"' +
1979+
' md-item-text="item.display"' +
1980+
' placeholder="placeholder"' +
1981+
' md-min-length="0"' +
1982+
' md-escape-options="clear"' +
1983+
' md-autoselect="false">' +
1984+
' <span md-highlight-text="searchText">{{item.display}}</span>' +
1985+
'</md-autocomplete>';
1986+
var scope = createScope();
1987+
var element = compile(template, scope);
1988+
var ctrl = element.controller('mdAutocomplete');
1989+
var input = element.find('input');
1990+
// Run our initial flush
1991+
$timeout.flush();
1992+
1993+
// Initial state
1994+
expect(ctrl.index).toBe(-1);
1995+
expect(ctrl.hidden).toBe(true);
1996+
expect(ctrl.activeOption).toBe(null);
1997+
1998+
ctrl.focus();
1999+
waitForVirtualRepeat(element);
2000+
2001+
// After getting focus
2002+
expect(ctrl.hidden).toBe(false);
2003+
expect(ctrl.index).toBe(-1);
2004+
expect(ctrl.activeOption).toBe(null);
2005+
2006+
// Highlighting the first item
2007+
ctrl.keydown(keydownEvent($mdConstant.KEY_CODE.DOWN_ARROW));
2008+
2009+
// Trying to go to the last item by cycling through the list
2010+
ctrl.keydown(keydownEvent($mdConstant.KEY_CODE.UP_ARROW));
2011+
$material.flushInterimElement();
2012+
2013+
// We should be on the last item
2014+
expect(ctrl.hidden).toBe(false);
2015+
expect(ctrl.index).toBe(2);
2016+
expect(ctrl.activeOption).toBe('md-option-' + ctrl.id + '-2');
2017+
2018+
element.remove();
2019+
});
2020+
2021+
it('should move to the first item when down arrow is pressed when on the last item', function() {
2022+
var template =
2023+
'<md-autocomplete' +
2024+
' md-selected-item="selectedItem"' +
2025+
' md-search-text="searchText"' +
2026+
' md-items="item in match(searchText)"' +
2027+
' md-item-text="item.display"' +
2028+
' placeholder="placeholder"' +
2029+
' md-min-length="0"' +
2030+
' md-escape-options="clear"' +
2031+
' md-autoselect="false">' +
2032+
' <span md-highlight-text="searchText">{{item.display}}</span>' +
2033+
'</md-autocomplete>';
2034+
var scope = createScope();
2035+
var element = compile(template, scope);
2036+
var ctrl = element.controller('mdAutocomplete');
2037+
var input = element.find('input');
2038+
// Run our initial flush
2039+
$timeout.flush();
2040+
2041+
// Initial state
2042+
expect(ctrl.index).toBe(-1);
2043+
expect(ctrl.hidden).toBe(true);
2044+
expect(ctrl.activeOption).toBe(null);
2045+
2046+
ctrl.focus();
2047+
waitForVirtualRepeat(element);
2048+
2049+
// After getting focus
2050+
expect(ctrl.hidden).toBe(false);
2051+
expect(ctrl.index).toBe(-1);
2052+
expect(ctrl.activeOption).toBe(null);
2053+
2054+
// Highlighting the first item
2055+
ctrl.keydown(keydownEvent($mdConstant.KEY_CODE.DOWN_ARROW));
2056+
2057+
// Highlighting the last item from the list
2058+
ctrl.keydown(keydownEvent($mdConstant.KEY_CODE.DOWN_ARROW));
2059+
ctrl.keydown(keydownEvent($mdConstant.KEY_CODE.DOWN_ARROW));
2060+
2061+
// Trying to go to the first item by cycling through the list
2062+
ctrl.keydown(keydownEvent($mdConstant.KEY_CODE.DOWN_ARROW));
2063+
$material.flushInterimElement();
2064+
2065+
// We should be on the first item
2066+
expect(ctrl.hidden).toBe(false);
2067+
expect(ctrl.index).toBe(0);
2068+
expect(ctrl.activeOption).toBe('md-option-' + ctrl.id + '-0');
2069+
2070+
element.remove();
2071+
});
2072+
19732073
it('should set activeOption when autoselect is on', function() {
19742074
var template =
19752075
'<md-autocomplete' +

src/components/autocomplete/js/autocompleteController.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,15 +640,15 @@ function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $mdTheming,
640640
if (ctrl.loading || hasSelection()) return;
641641
event.stopPropagation();
642642
event.preventDefault();
643-
ctrl.index = Math.min(ctrl.index + 1, ctrl.matches.length - 1);
643+
ctrl.index = ctrl.index + 1 > ctrl.matches.length - 1 ? 0 : Math.min(ctrl.index + 1, ctrl.matches.length - 1);
644644
$mdUtil.nextTick(updateActiveOption);
645645
updateScroll();
646646
break;
647647
case $mdConstant.KEY_CODE.UP_ARROW:
648648
if (ctrl.loading || hasSelection()) return;
649649
event.stopPropagation();
650650
event.preventDefault();
651-
ctrl.index = ctrl.index < 0 ? ctrl.matches.length - 1 : Math.max(0, ctrl.index - 1);
651+
ctrl.index = ctrl.index - 1 < 0 ? ctrl.matches.length - 1 : Math.max(0, ctrl.index - 1);
652652
$mdUtil.nextTick(updateActiveOption);
653653
updateScroll();
654654
break;

0 commit comments

Comments
 (0)