From 643cf520093a7c703731152f3e689bbf837d431e Mon Sep 17 00:00:00 2001 From: varnastadeus Date: Fri, 5 Jul 2019 20:10:22 +0300 Subject: [PATCH] feat: expose blur method BREAKING CHANGE: `filterValue` is now available as `searchTerm` closes #1238, closes #1242 --- README.md | 1 + src/ng-select/lib/ng-select.component.html | 50 +++++++++---------- src/ng-select/lib/ng-select.component.spec.ts | 34 ++++++------- src/ng-select/lib/ng-select.component.ts | 47 +++++++++-------- 4 files changed, 69 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 330641cbb..2a9ed97f2 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,7 @@ map: { | open | Opens the select dropdown panel | | close | Closes the select dropdown panel | | focus | Focuses the select element | +| blur | Blurs the select element | ### Other Name | Type | Description | diff --git a/src/ng-select/lib/ng-select.component.html b/src/ng-select/lib/ng-select.component.html index c2eb5e3a2..2622f1451 100644 --- a/src/ng-select/lib/ng-select.component.html +++ b/src/ng-select/lib/ng-select.component.html @@ -22,7 +22,7 @@
- + class="ng-dropdown-panel" + [virtualScroll]="virtualScroll" + [bufferAmount]="bufferAmount" + [appendTo]="appendTo" + [position]="dropdownPosition" + [headerTemplate]="headerTemplate" + [footerTemplate]="footerTemplate" + [filterValue]="searchTerm" + [items]="itemsList.filteredItems" + [markedItem]="itemsList.markedItem" + (update)="viewPortItems = $event" + (scroll)="scroll.emit($event)" + (scrollToEnd)="scrollToEnd.emit($event)" + (outsideClick)="close()" + [class.ng-select-multiple]="multiple" + [ngClass]="appendTo ? classes : null" + [id]="dropdownId">
+ [ngTemplateOutletContext]="{ item: item.value, item$:item, index: item.index, searchTerm: searchTerm }">
- {{addTagText}}"{{filterValue}}" + {{addTagText}}"{{searchTerm}}" + [ngTemplateOutletContext]="{ searchTerm: searchTerm }">
@@ -122,7 +122,7 @@ + [ngTemplateOutletContext]="{ searchTerm: searchTerm }"> @@ -143,7 +143,7 @@ + [ngTemplateOutletContext]="{ searchTerm: searchTerm }"> diff --git a/src/ng-select/lib/ng-select.component.spec.ts b/src/ng-select/lib/ng-select.component.spec.ts index b21603716..021013638 100644 --- a/src/ng-select/lib/ng-select.component.spec.ts +++ b/src/ng-select/lib/ng-select.component.spec.ts @@ -1382,7 +1382,7 @@ describe('NgSelectComponent', () => { })); it('should not remove selected value if filter is set', fakeAsync(() => { - select.filterValue = 'a'; + select.searchTerm = 'a'; fixture.componentInstance.selectedCity = fixture.componentInstance.cities[0]; tickAndDetectChanges(fixture); triggerKeyDownEvent(getNgSelectElement(fixture), KeyCode.Backspace); @@ -1758,7 +1758,7 @@ describe('NgSelectComponent', () => { `); - fixture.componentInstance.select.filterValue = 'tag'; + fixture.componentInstance.select.searchTerm = 'tag'; fixture.componentInstance.select.open(); fixture.detectChanges(); @@ -2198,23 +2198,23 @@ describe('NgSelectComponent', () => { }); it('should be false when there is no search term', () => { - select.filterValue = null; + select.searchTerm = null; expect(select.showAddTag).toBeFalsy(); }); it('should be true when term not exists among items', () => { - select.filterValue = 'Vil'; + select.searchTerm = 'Vil'; expect(select.showAddTag).toBeTruthy(); }); it('should be false when term exists among items', () => { - select.filterValue = 'Vilnius'; + select.searchTerm = 'Vilnius'; expect(select.showAddTag).toBeFalsy(); }); it('should be false when term exists among selected items', fakeAsync(() => { fixture.componentInstance.selectedCities = [{ name: 'Palanga', id: 9 }]; - select.filterValue = 'Palanga'; + select.searchTerm = 'Palanga'; select.hideSelected = true; select.isOpen = true; tickAndDetectChanges(fixture); @@ -2223,7 +2223,7 @@ describe('NgSelectComponent', () => { it('should be false when term exists among selected items and select is closed', fakeAsync(() => { fixture.componentInstance.selectedCities = [{ name: 'Palanga', id: 9 }]; - select.filterValue = 'Palanga'; + select.searchTerm = 'Palanga'; select.hideSelected = false; select.isOpen = false; tickAndDetectChanges(fixture); @@ -2364,7 +2364,7 @@ describe('NgSelectComponent', () => { fixture.detectChanges(); const input: HTMLInputElement = select.element.querySelector('input'); - expect(select.filterValue).toBeNull(); + expect(select.searchTerm).toBeNull(); expect(input.readOnly).toBeTruthy(); })); @@ -2451,10 +2451,10 @@ describe('NgSelectComponent', () => { tickAndDetectChanges(fixture); - fixture.componentInstance.select.filterValue = 'Hey! Whats up!?'; + fixture.componentInstance.select.searchTerm = 'Hey! Whats up!?'; selectOption(fixture, KeyCode.ArrowDown, 1); tickAndDetectChanges(fixture); - expect(fixture.componentInstance.select.filterValue).toBe(null); + expect(fixture.componentInstance.select.searchTerm).toBe(null); })); it('should not reset items when selecting option', fakeAsync(() => { @@ -2469,7 +2469,7 @@ describe('NgSelectComponent', () => { const resetFilteredItemsSpy = spyOn(fixture.componentInstance.select.itemsList, 'resetFilteredItems'); tickAndDetectChanges(fixture); - fixture.componentInstance.select.filterValue = null; + fixture.componentInstance.select.searchTerm = null; selectOption(fixture, KeyCode.ArrowDown, 1); tickAndDetectChanges(fixture); expect(resetFilteredItemsSpy).not.toHaveBeenCalled(); @@ -2618,10 +2618,10 @@ describe('NgSelectComponent', () => { fixture.componentInstance.cities = [{ id: 4, name: 'New York' }]; tickAndDetectChanges(fixture); expect(fixture.componentInstance.select.itemsList.filteredItems.length).toBe(1); - expect(fixture.componentInstance.select.filterValue).toBe('new'); + expect(fixture.componentInstance.select.searchTerm).toBe('new'); fixture.componentInstance.select.select(fixture.componentInstance.select.viewPortItems[0]); - expect(fixture.componentInstance.select.filterValue).toBeNull(); + expect(fixture.componentInstance.select.searchTerm).toBeNull(); })); it('should not clear search term by default when closeOnSelect is false ', fakeAsync(() => { @@ -2644,7 +2644,7 @@ describe('NgSelectComponent', () => { fixture.componentInstance.select.select(fixture.componentInstance.select.viewPortItems[0]); expect(fixture.componentInstance.select.itemsList.filteredItems.length).toBe(1); - expect(fixture.componentInstance.select.filterValue).toBe('new'); + expect(fixture.componentInstance.select.searchTerm).toBe('new'); })); it('should not clear search term when clearSearchOnAdd is false', fakeAsync(() => { @@ -2667,7 +2667,7 @@ describe('NgSelectComponent', () => { fixture.componentInstance.cities = [{ id: 4, name: 'New York' }, { id: 5, name: 'California' }]; tickAndDetectChanges(fixture); fixture.componentInstance.select.select(fixture.componentInstance.select.viewPortItems[0]); - expect(fixture.componentInstance.select.filterValue).toBe('new'); + expect(fixture.componentInstance.select.searchTerm).toBe('new'); })); }); }); @@ -3036,12 +3036,12 @@ describe('NgSelectComponent', () => { it('should clear only search text', fakeAsync(() => { fixture.componentInstance.selectedCities = null; - fixture.componentInstance.select.filterValue = 'Hey! Whats up!?'; + fixture.componentInstance.select.searchTerm = 'Hey! Whats up!?'; tickAndDetectChanges(fixture); triggerMousedown(); tickAndDetectChanges(fixture); expect(fixture.componentInstance.onChange).toHaveBeenCalledTimes(0); - expect(fixture.componentInstance.select.filterValue).toBe(null); + expect(fixture.componentInstance.select.searchTerm).toBe(null); })); it('should not open dropdown', fakeAsync(() => { diff --git a/src/ng-select/lib/ng-select.component.ts b/src/ng-select/lib/ng-select.component.ts index 273b02136..42664b52a 100644 --- a/src/ng-select/lib/ng-select.component.ts +++ b/src/ng-select/lib/ng-select.component.ts @@ -167,14 +167,15 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C @ViewChild(forwardRef(() => NgDropdownPanelComponent), { static: false }) dropdownPanel: NgDropdownPanelComponent; @ContentChildren(NgOptionComponent, { descendants: true }) ngOptions: QueryList; - @ViewChild('filterInput', { static: true }) filterInput: ElementRef; + @ViewChild('searchInput', { static: true }) searchInput: ElementRef; @HostBinding('class.ng-select-disabled') disabled = false; - @HostBinding('class.ng-select-filtered') get filtered() { return !!this.filterValue && this.searchable }; + + @HostBinding('class.ng-select-filtered') get filtered() { return !!this.searchTerm && this.searchable }; itemsList: ItemsList; viewPortItems: NgOption[] = []; - filterValue: string = null; + searchTerm: string = null; dropdownId = newId(); element: HTMLElement; focused: boolean; @@ -395,7 +396,7 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C this.isOpen = true; this.itemsList.markSelectedOrDefault(this.markFirst); this.openEvent.emit(); - if (!this.filterValue) { + if (!this.searchTerm) { this.focus(); } this.detectChanges(); @@ -446,7 +447,11 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C } focus() { - this.filterInput.nativeElement.focus(); + this.searchInput.nativeElement.focus(); + } + + blur() { + this.searchInput.nativeElement.blur(); } unselect(item: NgOption) { @@ -463,9 +468,9 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C selectTag() { let tag; if (isFunction(this.addTag)) { - tag = (this.addTag)(this.filterValue); + tag = (this.addTag)(this.searchTerm); } else { - tag = this._primitive ? this.filterValue : { [this.bindLabel]: this.filterValue }; + tag = this._primitive ? this.searchTerm : { [this.bindLabel]: this.searchTerm }; } const handleTag = (item) => this._isTypeahead || !this.isOpen ? this.itemsList.mapItem(item, null) : this.itemsList.addItem(item); @@ -477,7 +482,7 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C } showClear() { - return this.clearable && (this.hasValue || this.filterValue) && !this.disabled; + return this.clearable && (this.hasValue || this.searchTerm) && !this.disabled; } trackByOption = (_: number, item: NgOption) => { @@ -489,11 +494,11 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C }; get showAddTag() { - if (!this.filterValue) { + if (!this.searchTerm) { return false; } - const term = this.filterValue.toLowerCase(); + const term = this.searchTerm.toLowerCase(); return this.addTag && (!this.itemsList.filteredItems.some(x => x.label.toLowerCase() === term) && (!this.hideSelected && this.isOpen || !this.selectedItems.some(x => x.label.toLowerCase() === term))) && @@ -503,22 +508,22 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C showNoItemsFound() { const empty = this.itemsList.filteredItems.length === 0; return ((empty && !this._isTypeahead && !this.loading) || - (empty && this._isTypeahead && this.filterValue && !this.loading)) && + (empty && this._isTypeahead && this.searchTerm && !this.loading)) && !this.showAddTag; } showTypeToSearch() { const empty = this.itemsList.filteredItems.length === 0; - return empty && this._isTypeahead && !this.filterValue && !this.loading; + return empty && this._isTypeahead && !this.searchTerm && !this.loading; } filter(term: string) { - this.filterValue = term; + this.searchTerm = term; if (this._isTypeahead) { - this.typeahead.next(this.filterValue); + this.typeahead.next(this.searchTerm); } else { - this.itemsList.filter(this.filterValue); + this.itemsList.filter(this.searchTerm); if (this.isOpen) { this.itemsList.markSelectedOrDefault(this.markFirst); } @@ -569,8 +574,8 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C if (items.length > 0 && this.hasValue) { this.itemsList.mapSelectedItems(); } - if (this.isOpen && isDefined(this.filterValue) && !this._isTypeahead) { - this.itemsList.filter(this.filterValue); + if (this.isOpen && isDefined(this.searchTerm) && !this._isTypeahead) { + this.itemsList.filter(this.searchTerm); } if (this._isTypeahead || this.isOpen) { this.itemsList.markSelectedOrDefault(this.markFirst); @@ -721,11 +726,11 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C } private _clearSearch() { - if (!this.filterValue) { + if (!this.searchTerm) { return; } - this.filterValue = null; + this.searchTerm = null; this.itemsList.resetFilteredItems(); } @@ -824,13 +829,13 @@ export class NgSelectComponent implements OnDestroy, OnChanges, AfterViewInit, C private _nextItemIsTag(nextStep: number): boolean { const nextIndex = this.itemsList.markedIndex + nextStep; - return this.addTag && this.filterValue + return this.addTag && this.searchTerm && this.itemsList.markedItem && (nextIndex < 0 || nextIndex === this.itemsList.filteredItems.length) } private _handleBackspace() { - if (this.filterValue || !this.clearable || !this.clearOnBackspace || !this.hasValue) { + if (this.searchTerm || !this.clearable || !this.clearOnBackspace || !this.hasValue) { return; }