diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.html index 51e7667200..449481152d 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.html @@ -28,7 +28,8 @@ aria-hidden="true" [authorityValue]="currentValue" (whenClickOnConfidenceNotAccepted)="whenClickOnConfidenceNotAccepted($event)"> - { inputElement.value = 'test value'; inputElement.dispatchEvent(new Event('input')); - expect((typeaheadComp.model as any).value).toEqual(new FormFieldMetadataValueObject('test value')) + expect(typeaheadComp.inputValue).toEqual(new FormFieldMetadataValueObject('test value')) }); @@ -173,19 +173,56 @@ describe('DsDynamicTypeaheadComponent test suite', () => { }); - it('should emit blur Event onBlur', () => { + it('should emit blur Event onBlur when popup is closed', () => { spyOn(typeaheadComp.blur, 'emit'); + spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false); typeaheadComp.onBlur(new Event('blur')); expect(typeaheadComp.blur.emit).toHaveBeenCalled(); }); - it('should emit change Event onBlur when AuthorityOptions.closed is false', () => { + it('should not emit blur Event onBlur when popup is opened', () => { + spyOn(typeaheadComp.blur, 'emit'); + spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(true); + const input = typeaheadFixture.debugElement.query(By.css('input')); + + input.nativeElement.blur(); + expect(typeaheadComp.blur.emit).not.toHaveBeenCalled(); + }); + + it('should emit change Event onBlur when AuthorityOptions.closed is false and inputValue is changed', () => { typeaheadComp.inputValue = 'test value'; typeaheadFixture.detectChanges(); spyOn(typeaheadComp.blur, 'emit'); spyOn(typeaheadComp.change, 'emit'); - typeaheadComp.onBlur(new Event('blur')); - // expect(typeaheadComp.change.emit).toHaveBeenCalled(); + spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false); + typeaheadComp.onBlur(new Event('blur', )); + expect(typeaheadComp.change.emit).toHaveBeenCalled(); + expect(typeaheadComp.blur.emit).toHaveBeenCalled(); + }); + + it('should not emit change Event onBlur when AuthorityOptions.closed is false and inputValue is not changed', () => { + typeaheadComp.inputValue = 'test value'; + typeaheadComp.model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG); + (typeaheadComp.model as any).value = 'test value'; + typeaheadFixture.detectChanges(); + spyOn(typeaheadComp.blur, 'emit'); + spyOn(typeaheadComp.change, 'emit'); + spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false); + typeaheadComp.onBlur(new Event('blur', )); + expect(typeaheadComp.change.emit).not.toHaveBeenCalled(); + expect(typeaheadComp.blur.emit).toHaveBeenCalled(); + }); + + it('should not emit change Event onBlur when AuthorityOptions.closed is false and inputValue is null', () => { + typeaheadComp.inputValue = null; + typeaheadComp.model = new DynamicTypeaheadModel(TYPEAHEAD_TEST_MODEL_CONFIG); + (typeaheadComp.model as any).value = 'test value'; + typeaheadFixture.detectChanges(); + spyOn(typeaheadComp.blur, 'emit'); + spyOn(typeaheadComp.change, 'emit'); + spyOn(typeaheadComp.instance, 'isPopupOpen').and.returnValue(false); + typeaheadComp.onBlur(new Event('blur', )); + expect(typeaheadComp.change.emit).not.toHaveBeenCalled(); expect(typeaheadComp.blur.emit).toHaveBeenCalled(); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts index ace6812858..136d1db1c2 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { @@ -8,14 +8,13 @@ import { } from '@ng-dynamic-forms/core'; import { catchError, debounceTime, distinctUntilChanged, filter, map, merge, switchMap, tap } from 'rxjs/operators'; import { Observable, of as observableOf, Subject } from 'rxjs'; -import { NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap'; +import { NgbTypeahead, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap'; import { AuthorityService } from '../../../../../../core/integration/authority.service'; import { DynamicTypeaheadModel } from './dynamic-typeahead.model'; import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model'; -import { isEmpty, isNotEmpty } from '../../../../../empty.util'; +import { isEmpty, isNotEmpty, isNotNull } from '../../../../../empty.util'; import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model'; - import { ConfidenceType } from '../../../../../../core/integration/models/confidence-type'; @Component({ @@ -32,6 +31,8 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp @Output() change: EventEmitter = new EventEmitter(); @Output() focus: EventEmitter = new EventEmitter(); + @ViewChild('instance') instance: NgbTypeahead; + searching = false; searchOptions: IntegrationSearchOptions; searchFailed = false; @@ -105,16 +106,26 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp onInput(event) { if (!this.model.authorityOptions.closed && isNotEmpty(event.target.value)) { this.inputValue = new FormFieldMetadataValueObject(event.target.value); - this.model.valueUpdates.next(this.inputValue); } } onBlur(event: Event) { - if (!this.model.authorityOptions.closed && isNotEmpty(this.inputValue)) { - this.change.emit(this.inputValue); - this.inputValue = null; + if (!this.instance.isPopupOpen()) { + if (!this.model.authorityOptions.closed && isNotEmpty(this.inputValue)) { + if (isNotNull(this.inputValue) && this.model.value !== this.inputValue) { + this.model.valueUpdates.next(this.inputValue); + this.change.emit(this.inputValue); + } + this.inputValue = null; + } + this.blur.emit(event); + } else { + // prevent on blur propagation if typeahed suggestions are showed + event.preventDefault(); + event.stopImmediatePropagation(); + // set focus on input again, this is to avoid to lose changes when no suggestion is selected + (event.target as HTMLInputElement).focus(); } - this.blur.emit(event); } onChange(event: Event) { @@ -141,4 +152,5 @@ export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent imp this.click$.next(this.formatter(this.currentValue)); } } + }