Skip to content

Commit

Permalink
feat: support item navigation while not searchable (#499)
Browse files Browse the repository at this point in the history
* feat: support item navigation while not searchable
closes #117
  • Loading branch information
varnastadeus committed Apr 26, 2018
1 parent 47f2e59 commit 38c27dc
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 12 deletions.
8 changes: 8 additions & 0 deletions src/ng-select/items-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ export class ItemsList {
}
}

findByLabel(term: string) {
term = searchHelper.stripSpecialChars(term).toLocaleLowerCase();
return this.filteredItems.find(item => {
const label = searchHelper.stripSpecialChars(item.label).toLocaleLowerCase();
return label.substr(0, term.length) === term;
});
}

filter(term: string) {
if (!term) {
this.resetItems();
Expand Down
27 changes: 27 additions & 0 deletions src/ng-select/ng-select.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,33 @@ describe('NgSelectComponent', function () {
expect(select.selectedItems).toEqual(result);
}));
});

describe('key presses', () => {
beforeEach(() => {
select.searchable = false;
select.ngOnInit();
});

it('should select item using key while not opened', fakeAsync(() => {
triggerKeyDownEvent(getNgSelectElement(fixture), 97, 'v');
tick(200);

expect(fixture.componentInstance.selectedCity.name).toBe('Vilnius');
}));

it('should mark item using key while opened', fakeAsync(() => {
const findByLabel = spyOn(select.itemsList, 'findByLabel');
triggerKeyDownEvent(getNgSelectElement(fixture), KeyCode.Space);
triggerKeyDownEvent(getNgSelectElement(fixture), 97, 'v');
triggerKeyDownEvent(getNgSelectElement(fixture), 97, 'i');
triggerKeyDownEvent(getNgSelectElement(fixture), 97, 'l');
tick(200);

expect(fixture.componentInstance.selectedCity).toBeUndefined();
expect(select.itemsList.markedItem.label).toBe('Vilnius')
expect(findByLabel).toHaveBeenCalledWith('vil')
}));
});
});

describe('Outside click', () => {
Expand Down
51 changes: 41 additions & 10 deletions src/ng-select/ng-select.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { Subject } from 'rxjs/Subject';
import { merge } from 'rxjs/observable/merge';
import { takeUntil, startWith } from 'rxjs/operators';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import {
Component,
OnDestroy,
Expand All @@ -28,6 +24,10 @@ import {
NgZone,
Attribute
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { takeUntil, startWith, tap, debounceTime, map, filter } from 'rxjs/operators';
import { merge } from 'rxjs/observable/merge';
import { Subject } from 'rxjs/Subject';

import {
NgOptionTemplateDirective,
Expand All @@ -41,13 +41,13 @@ import {
NgMultiLabelTemplateDirective
} from './ng-templates.directive';

import { NgOption, KeyCode, NgSelectConfig } from './ng-select.types';
import { ItemsList } from './items-list';
import { NgOptionComponent } from './ng-option.component';
import { NgDropdownPanelComponent } from './ng-dropdown-panel.component';
import { isDefined, isFunction, isPromise, isObject } from './value-utils';
import { ConsoleService } from './console.service';
import { isDefined, isFunction, isPromise, isObject } from './value-utils';
import { ItemsList } from './items-list';
import { NgOption, KeyCode, NgSelectConfig } from './ng-select.types';
import { newId } from './id';
import { NgDropdownPanelComponent } from './ng-dropdown-panel.component';
import { NgOptionComponent } from './ng-option.component';
import { WindowService } from './window.service';

export const NG_SELECT_DEFAULT_CONFIG = new InjectionToken<NgSelectConfig>('ng-select-default-options');
Expand Down Expand Up @@ -152,9 +152,11 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C

private _defaultLabel = 'label';
private _primitive: boolean;
private _pressedKeys: string[] = [];
private _compareWith: CompareWithFn;

private readonly _destroy$ = new Subject<void>();
private readonly _keyPress$ = new Subject<string>();
private _onChange = (_: NgOption) => { };
private _onTouched = () => { };

Expand Down Expand Up @@ -187,6 +189,10 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C
return this.selectedItems.length > 0;
}

ngOnInit() {
this._handleKeyPresses();
}

ngOnChanges(changes: SimpleChanges) {
if (changes.multiple) {
this.itemsList.clearSelected();
Expand Down Expand Up @@ -233,6 +239,8 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C
this._handleBackspace();
break;
}
} else if ($event.key && $event.key.length === 1) {
this._keyPress$.next($event.key.toLocaleLowerCase());
}
}

Expand Down Expand Up @@ -573,7 +581,30 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C
}
}


_handleKeyPresses() {
if (this.searchable) {
return;
}

this._keyPress$
.pipe(takeUntil(this._destroy$),
tap(letter => this._pressedKeys.push(letter)),
debounceTime(200),
filter(() => this._pressedKeys.length > 0),
map(() => this._pressedKeys.join('')))
.subscribe(term => {
const item = this.itemsList.findByLabel(term);
if (item) {
if (this.isOpen) {
this.itemsList.markItem(item);
this._cd.markForCheck();
} else {
this.select(item);
}
}
this._pressedKeys = [];
});
}

private _updateNgModel() {
const model = [];
Expand Down
5 changes: 3 additions & 2 deletions src/testing/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ export function getNgSelectElement(fixture: ComponentFixture<any>): DebugElement
return fixture.debugElement.query(By.css('ng-select'));
}

export function triggerKeyDownEvent(element: DebugElement, key: number): void {
export function triggerKeyDownEvent(element: DebugElement, which: number, key = ''): void {
element.triggerEventHandler('keydown', {
which: key,
which: which,
key: key,
preventDefault: () => { },
stopPropagation: () => { }
});
Expand Down

0 comments on commit 38c27dc

Please sign in to comment.