Skip to content

Commit

Permalink
fix(autocomplete): up arrow should set last item active
Browse files Browse the repository at this point in the history
  • Loading branch information
kara committed Jan 25, 2017
1 parent 71fb0a6 commit 7ed5f6e
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 6 deletions.
6 changes: 3 additions & 3 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class MdAutocompleteTrigger implements AfterContentInit, OnDestroy {
@Optional() private _controlDir: NgControl, @Optional() private _dir: Dir) {}

ngAfterContentInit() {
this._keyManager = new ActiveDescendantKeyManager(this.autocomplete.options);
this._keyManager = new ActiveDescendantKeyManager(this.autocomplete.options).withWrap();
}

ngOnDestroy() {
Expand Down Expand Up @@ -235,9 +235,9 @@ export class MdAutocompleteTrigger implements AfterContentInit, OnDestroy {
return this._element.nativeElement.getBoundingClientRect().width;
}

/** Reset active item to -1 so DOWN_ARROW event will activate the first option.*/
/** Reset active item to null so arrow events will activate the correct options.*/
private _resetActiveItem(): void {
this._keyManager.setActiveItem(-1);
this._keyManager.setActiveItem(null);
}

/**
Expand Down
32 changes: 31 additions & 1 deletion src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {MdInputModule} from '../input/index';
import {Dir, LayoutDirection} from '../core/rtl/dir';
import {FormControl, ReactiveFormsModule} from '@angular/forms';
import {Subscription} from 'rxjs/Subscription';
import {ENTER, DOWN_ARROW, SPACE} from '../core/keyboard/keycodes';
import {ENTER, DOWN_ARROW, SPACE, UP_ARROW} from '../core/keyboard/keycodes';
import {MdOption} from '../core/option/option';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';

Expand Down Expand Up @@ -294,6 +294,36 @@ describe('MdAutocomplete', () => {
});
}));

it('should set the active item to the last option when UP key is pressed', async(() => {
fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();

const optionEls =
overlayContainerElement.querySelectorAll('md-option') as NodeListOf<HTMLElement>;

const UP_ARROW_EVENT = new FakeKeyboardEvent(UP_ARROW) as KeyboardEvent;
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);

fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.componentInstance.trigger.activeOption)
.toBe(fixture.componentInstance.options.last, 'Expected last option to be active.');
expect(optionEls[10].classList).toContain('md-active');
expect(optionEls[0].classList).not.toContain('md-active');

fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);

fixture.whenStable().then(() => {
fixture.detectChanges();
expect(fixture.componentInstance.trigger.activeOption)
.toBe(fixture.componentInstance.options.first,
'Expected first option to be active.');
expect(optionEls[0].classList).toContain('md-active');
expect(optionEls[10].classList).not.toContain('md-active');
});
});
}));

it('should set the active item properly after filtering', async(() => {
fixture.componentInstance.trigger.openPanel();
fixture.detectChanges();
Expand Down
27 changes: 27 additions & 0 deletions src/lib/core/a11y/list-key-manager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ describe('Key managers', () => {
expect(keyManager.setActiveItem).not.toHaveBeenCalledWith(0);
});

it('should set first item active when down arrow pressed if no active item', () => {
keyManager.setActiveItem(null);
keyManager.onKeydown(DOWN_ARROW_EVENT);

expect(keyManager.activeItemIndex)
.toBe(0, 'Expected active item to be 0 after down key if active item was null.');
expect(keyManager.setActiveItem).toHaveBeenCalledWith(0);
expect(keyManager.setActiveItem).not.toHaveBeenCalledWith(1);
expect(keyManager.setActiveItem).not.toHaveBeenCalledWith(2);
});

it('should set previous items as active when up arrow is pressed', () => {
keyManager.onKeydown(DOWN_ARROW_EVENT);

Expand Down Expand Up @@ -347,6 +358,22 @@ describe('Key managers', () => {
expect(keyManager.activeItemIndex).toBe(2, 'Expected active item to wrap to end.');
});

it('should set last item active when up arrow is pressed if no active item', () => {
keyManager.withWrap();
keyManager.setActiveItem(null);
keyManager.onKeydown(UP_ARROW_EVENT);

expect(keyManager.activeItemIndex)
.toBe(2, 'Expected last item to be active on up arrow if no active item.');
expect(keyManager.setActiveItem).not.toHaveBeenCalledWith(0);
expect(keyManager.setActiveItem).toHaveBeenCalledWith(2);

keyManager.onKeydown(DOWN_ARROW_EVENT);
expect(keyManager.activeItemIndex)
.toBe(0, 'Expected active item to be 0 after wrapping back to beginning.');
expect(keyManager.setActiveItem).toHaveBeenCalledWith(0);
});

});

});
Expand Down
5 changes: 3 additions & 2 deletions src/lib/core/a11y/list-key-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,13 @@ export class ListKeyManager<T extends CanDisable> {

/** Sets the active item to the next enabled item in the list. */
setNextItemActive(): void {
this._setActiveItemByDelta(1);
this._activeItemIndex === null ? this.setFirstItemActive() : this._setActiveItemByDelta(1);
}

/** Sets the active item to a previous enabled item in the list. */
setPreviousItemActive(): void {
this._setActiveItemByDelta(-1);
this._activeItemIndex === null && this._wrap ? this.setLastItemActive()
: this._setActiveItemByDelta(-1);
}

/**
Expand Down

0 comments on commit 7ed5f6e

Please sign in to comment.