diff --git a/projects/igniteui-angular/src/lib/combo/combo-dropdown.component.ts b/projects/igniteui-angular/src/lib/combo/combo-dropdown.component.ts index 072863f63f2..0f1359b3411 100644 --- a/projects/igniteui-angular/src/lib/combo/combo-dropdown.component.ts +++ b/projects/igniteui-angular/src/lib/combo/combo-dropdown.component.ts @@ -53,11 +53,15 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I this.items.length - 1; } - @ContentChildren(IgxComboItemComponent, { descendants: true }) - protected children: QueryList = null; - private _scrollPosition = 0; + /** + * @hidden + * @internal + */ + @ContentChildren(IgxComboItemComponent, { descendants: true }) + public children: QueryList = null; + /** * @hidden */ diff --git a/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.spec.ts b/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.spec.ts index a2f9afb0c47..d4aa4fcd409 100644 --- a/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.spec.ts @@ -9,7 +9,7 @@ import { IgxInputGroupModule } from '../../input-group'; import { IgxDropDownModule, IgxDropDownComponent } from '../../drop-down'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -fdescribe('IgxAutocomplete', () => { +describe('IgxAutocomplete', () => { let fixture; let autocomplete: IgxAutocompleteDirective; let input: IgxInputDirective; @@ -69,17 +69,43 @@ fdescribe('IgxAutocomplete', () => { expect(dropDown.collapsed).toBeTruthy(); })); - it('Auto-highlighting first item', fakeAsync(() => { + it('Auto-highlight first item', fakeAsync(() => { UIInteractions.sendInput(input, 's', fixture); fixture.detectChanges(); tick(); + expect(dropDown.children.first.focused).toBeTruthy(); expect(dropDown.items[0].focused).toBeTruthy(); + expect(dropDown.items[0].value).toBe('Sofia'); UIInteractions.triggerKeyDownEvtUponElem('enter', input.nativeElement, true); fixture.detectChanges(); tick(); expect(fixture.componentInstance.townSelected).toBe('Sofia'); + + UIInteractions.sendInput(input, 'st', fixture); + fixture.detectChanges(); + tick(); + expect(dropDown.children.first.focused).toBeTruthy(); + expect(dropDown.items[0].focused).toBeTruthy(); + expect(dropDown.items[0].value).toBe('Stara Zagora'); + + UIInteractions.sendInput(input, 's', fixture); + fixture.detectChanges(); + tick(); + expect(dropDown.children.first.focused).toBeTruthy(); + expect(dropDown.items[0].focused).toBeTruthy(); + expect(dropDown.items[0].value).toBe('Sofia'); + expect(dropDown.items[1].focused).toBeFalsy(); + expect(dropDown.items[1].value).toBe('Stara Zagora'); })); + + it('Disabled', fakeAsync(() => {})); + it('Selection and events', fakeAsync(() => {})); + it('Keyboard Navigation', fakeAsync(() => {})); + it('DropDown settings', fakeAsync(() => {})); + it('DropDown default width', fakeAsync(() => {})); + it('Aria', fakeAsync(() => {})); + it('ReactiveForm', fakeAsync(() => {})); }); }); diff --git a/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.ts b/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.ts index b76d70d140b..db02f9a5bd4 100644 --- a/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/autocomplete/autocomplete.directive.ts @@ -1,15 +1,16 @@ //#region imports import { Directive, Input, Self, Optional, Inject, HostBinding, Output, EventEmitter, - NgModule, ElementRef, HostListener } from '@angular/core'; + NgModule, ElementRef, HostListener, ChangeDetectorRef } from '@angular/core'; import { NgModel, FormControlName } from '@angular/forms'; import { CommonModule } from '@angular/common'; -import { first } from 'rxjs/operators'; +import { first, takeUntil } from 'rxjs/operators'; import { CancelableEventArgs } from '../../core/utils'; import { OverlaySettings, AbsoluteScrollStrategy, ConnectedPositioningStrategy } from '../../services'; import { ISelectionEventArgs } from '../../drop-down'; import { IgxDropDownModule, IgxDropDownComponent } from '../../drop-down/drop-down.component'; import { IgxDropDownItemNavigationDirective } from '../../drop-down/drop-down-navigation.directive'; +import { Subject } from 'rxjs'; //#endregion /** @@ -27,11 +28,13 @@ export class IgxAutocompleteDirective extends IgxDropDownItemNavigationDirective constructor(@Self() @Optional() @Inject(NgModel) protected ngModel: NgModel, @Self() @Optional() @Inject(FormControlName) protected formControl: FormControlName, - protected elementRef: ElementRef) { + protected elementRef: ElementRef, + protected cdr: ChangeDetectorRef) { super(null); } protected id: string; + protected queryListNotifier$ = new Subject(); protected get model() { return this.ngModel ? this.ngModel : this.formControl; } @@ -41,7 +44,7 @@ export class IgxAutocompleteDirective extends IgxDropDownItemNavigationDirective } private get collapsed(): boolean { - return this.target ? this.target.collapsed : true; + return this.dropDown ? this.dropDown.collapsed : true; } @Input('igxAutocomplete') @@ -106,7 +109,7 @@ export class IgxAutocompleteDirective extends IgxDropDownItemNavigationDirective if (this.collapsed) { this.open(); } else { - this.highlightFirstItem(); + this.unhighlightFirstItem(); } } @HostListener('blur', ['$event']) @@ -123,6 +126,7 @@ export class IgxAutocompleteDirective extends IgxDropDownItemNavigationDirective private close() { this.dropDown.close(); + this.queryListNotifier$.complete(); } private open() { @@ -133,13 +137,14 @@ export class IgxAutocompleteDirective extends IgxDropDownItemNavigationDirective this.dropDown.onOpened.pipe(first()).subscribe(() => { this.highlightFirstItem(); }); + this.dropDown.children.changes.pipe(takeUntil(this.queryListNotifier$)).subscribe(() => this.highlightFirstItem()); } private select = (value: ISelectionEventArgs) => { // ? if (!value.newSelection) { return; } - value.cancel = true; + value.cancel = true; // Disable selection in the drop down, because in auto complete we do not save selection. const newValue = value.newSelection.value; const args: IAutocompleteItemSelectionEventArgs = { value: newValue, cancel: false }; this.onItemSelected.emit(args); @@ -150,12 +155,20 @@ export class IgxAutocompleteDirective extends IgxDropDownItemNavigationDirective this.close(); } + private unhighlightFirstItem() { + const firstItem = this.dropDown.items[0]; + if (firstItem) { + firstItem.isFocused = false; + } + } + private highlightFirstItem() { - const firstMatch = this.target.items[0]; - if (firstMatch) { - firstMatch.isFocused = true; - this.target.focusedItem = firstMatch; + const firstItem = this.dropDown.items[0]; + if (firstItem) { + firstItem.isFocused = true; + this.dropDown.focusedItem = firstItem; } + this.cdr.detectChanges(); } } diff --git a/projects/igniteui-angular/src/lib/drop-down/drop-down.base.ts b/projects/igniteui-angular/src/lib/drop-down/drop-down.base.ts index be44e192fe1..c2c759e2ea6 100644 --- a/projects/igniteui-angular/src/lib/drop-down/drop-down.base.ts +++ b/projects/igniteui-angular/src/lib/drop-down/drop-down.base.ts @@ -21,7 +21,6 @@ export abstract class IgxDropDownBase implements IDropDownList { protected _height; protected _focusedItem: any = null; protected _id = `igx-drop-down-${NEXT_ID++}`; - protected children: QueryList; /** * Get dropdown's html element of it scroll container @@ -30,6 +29,12 @@ export abstract class IgxDropDownBase implements IDropDownList { return this.element; } + /** + * @hidden + * @internal + */ + public children: QueryList; + /** * Emitted when item selection is changing, before the selection completes * diff --git a/projects/igniteui-angular/src/lib/drop-down/drop-down.component.ts b/projects/igniteui-angular/src/lib/drop-down/drop-down.component.ts index cc33f4b2286..98013b9a416 100644 --- a/projects/igniteui-angular/src/lib/drop-down/drop-down.component.ts +++ b/projects/igniteui-angular/src/lib/drop-down/drop-down.component.ts @@ -49,13 +49,17 @@ import { OverlaySettings } from '../services'; providers: [{ provide: IGX_DROPDOWN_BASE, useExisting: IgxDropDownComponent }] }) export class IgxDropDownComponent extends IgxDropDownBase implements IDropDownBase, OnInit, OnDestroy { - @ContentChildren(forwardRef(() => IgxDropDownItemComponent)) - protected children: QueryList; - @ViewChild(IgxToggleDirective) protected toggleDirective: IgxToggleDirective; protected destroy$ = new Subject(); + /** + * @hidden + * @internal + */ + @ContentChildren(forwardRef(() => IgxDropDownItemComponent)) + public children: QueryList; + /** * Gets/sets whether items take focus. Disabled by default. * When enabled, drop down items gain tab index and are focused when active -