Skip to content

Commit

Permalink
feat(autocomplete): allow dynamic dir switching (#120)
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] authored and GitHub Enterprise committed Dec 1, 2020
1 parent aa48a39 commit bb1c7b0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function getNxAutocompleteMissingPanelError(): Error {
exportAs: 'nxAutocompleteTrigger',
providers: [NX_AUTOCOMPLETE_VALUE_ACCESSOR]
})
export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnDestroy, OnChanges, AfterViewInit {
export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnDestroy, OnChanges, AfterViewInit, OnInit {
private _overlayRef: OverlayRef | null;
private _portal: TemplatePortal;
private _componentDestroyed = false;
Expand Down Expand Up @@ -113,6 +113,9 @@ export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnD
/** Value changes */
private readonly _valueChanges: Subject<any> = new Subject<any>();

/** Subscription to direction changes */
private _dirChangeSubscription = Subscription.EMPTY;

/** The autocomplete panel to be attached to this trigger. */
@Input('nxAutocomplete') autocomplete: NxAutocompleteComponent;

Expand Down Expand Up @@ -230,7 +233,7 @@ export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnD
private _viewContainerRef: ViewContainerRef,
private _zone: NgZone,
private _changeDetectorRef: ChangeDetectorRef,
@Optional() private _dir: Directionality,
private _dir: Directionality,
@Optional() @Host() private _nxFormField: NxFormfieldComponent,
@Optional() @Host() private _nxWordField: NxWordComponent,
@Optional() @Inject(DOCUMENT) private _document: any,
Expand All @@ -242,6 +245,13 @@ export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnD
}
}

ngOnInit() {
this._dirChangeSubscription = this._dir.change.subscribe(() => {
this._flipDirection();
this._changeDetectorRef.markForCheck();
});
}

ngOnDestroy() {
if (typeof window !== 'undefined') {
window.removeEventListener('blur', this._windowBlurHandler);
Expand All @@ -250,8 +260,9 @@ export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnD
this._componentDestroyed = true;
this._destroyPanel();
this._closeKeyEventStream.complete();
if (this._controlValueChangesSubscription) { this._controlValueChangesSubscription.unsubscribe(); }
if (this._itemsSubscription) { this._itemsSubscription.unsubscribe(); }
this._controlValueChangesSubscription?.unsubscribe();
this._itemsSubscription?.unsubscribe();
this._dirChangeSubscription?.unsubscribe();
}

ngOnChanges() {
Expand Down Expand Up @@ -693,6 +704,11 @@ export class NxAutocompleteTriggerDirective implements ControlValueAccessor, OnD
return !element.readOnly && !element.disabled;
}

private _flipDirection(): void {
this._overlayRef?.setDirection(this._dir.value);
this._overlayRef?.updatePositionStrategy(this._getOverlayPosition());
}

static ngAcceptInputType_debounce: NumberInput;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { CommonModule } from '@angular/common';
import * as axe from 'axe-core';

import { NxAutocompleteComponent } from '.';
import { NxAutocompleteTriggerDirective } from '.';
import { NxInputModule } from '../input';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { NxModalModule } from '@aposin/ng-aquila/modal';
Expand All @@ -22,12 +23,14 @@ describe('NxAutocompleteComponent:', () => {
let testInstance: AutocompleteComponent;
let input: HTMLInputElement;
let overlayContainer: OverlayContainer;
let triggerInstance: NxAutocompleteTriggerDirective;

function createTestComponent(component: Type<AutocompleteComponent>) {
fixture = TestBed.createComponent(component);
fixture.autoDetectChanges();
testInstance = fixture.componentInstance;
input = fixture.nativeElement.querySelector('input');
triggerInstance = fixture.componentInstance.autocompleteTrigger;
}

function flush() {
Expand Down Expand Up @@ -57,7 +60,8 @@ describe('NxAutocompleteComponent:', () => {
ComplexDataAutocompleteComponent,
NgModelBindingAutocompleteComponent,
ReactiveAutocompleteComponent,
AutocompleteInModalComponent
AutocompleteInModalComponent,
AutocompleteComponentWithDirection,
],
imports: [
CommonModule,
Expand Down Expand Up @@ -248,6 +252,48 @@ describe('NxAutocompleteComponent:', () => {
});
});
});

describe('directionality of overlay', () => {
it('should be set to ltr by default', fakeAsync(() => {
createTestComponent(BasicAutocompleteComponent);
typeInput('A');
flush();
const direction = (triggerInstance as any)._overlayRef.getDirection();
expect(direction).toBe('ltr');
}));

it('should be set to rtl if container direction is rtl', fakeAsync(() => {
createTestComponent(AutocompleteComponentWithDirection);
typeInput('A');
flush();
const direction = (triggerInstance as any)._overlayRef.getDirection();
expect(direction).toBe('rtl');
}));
});

describe('when container direction changes', () => {
it('overlay direction should be updated respectively', fakeAsync(() => {
createTestComponent(AutocompleteComponentWithDirection);
typeInput('A');
flush();
(testInstance as AutocompleteComponentWithDirection).direction = 'ltr';
typeInput('A');
flush();
const direction = (triggerInstance as any)._overlayRef.getDirection();
expect(direction).toBe('ltr');
}));

it('overlay position strategy should be updated', fakeAsync(() => {
createTestComponent(AutocompleteComponentWithDirection);
typeInput('A');
flush();
spyOn((triggerInstance as any)._overlayRef, 'updatePositionStrategy');
(testInstance as AutocompleteComponentWithDirection).direction = 'ltr';
typeInput('A');
flush();
expect((triggerInstance as any)._overlayRef.updatePositionStrategy).toHaveBeenCalledTimes(1);
}));
});
});

const DATA = [
Expand All @@ -267,6 +313,7 @@ const COMPLEX_DATA = [
class AutocompleteComponent {
@ViewChild(NxAutocompleteComponent, { read: ElementRef }) autocompleteInstanceRef: ElementRef;
@ViewChild(NxAutocompleteComponent) autocompleteInstance: NxAutocompleteComponent;
@ViewChild(NxAutocompleteTriggerDirective) autocompleteTrigger: NxAutocompleteTriggerDirective;

public inputVal: any;

Expand Down Expand Up @@ -385,6 +432,19 @@ class AutocompleteInModalComponent extends AutocompleteComponent {
open = true;
}

@Component({
template: `
<div [dir]="direction">
<input type="text" [nxAutocomplete]="auto1" [nxAutocompleteItems]="searchFunction" [nxAutocompleteDisabled]="autocompleteDisabled"
nxAutocompleteDebounce="0" aria-label="atcmpl" />
<nx-autocomplete #auto1></nx-autocomplete>
</div>
`
})
class AutocompleteComponentWithDirection extends AutocompleteComponent {
direction = 'rtl';
}

function isVisible(el) {
if (getComputedStyle(el).visibility === 'hidden') {
return false;
Expand Down

0 comments on commit bb1c7b0

Please sign in to comment.