From 2264d1c18ae9ceca3dc88cc8297cf3e6e1b1c312 Mon Sep 17 00:00:00 2001 From: Kai Glass <50838996+Tuxio@users.noreply.github.com> Date: Sun, 2 Jul 2023 00:55:04 +0200 Subject: [PATCH] #2242 #12983 display selectedItem template in autocomplete input --- .../components/autocomplete/autocomplete.css | 21 +++- .../autocomplete/autocomplete.spec.ts | 101 ++++++++++++++++- .../components/autocomplete/autocomplete.ts | 103 ++++++++++++++---- 3 files changed, 197 insertions(+), 28 deletions(-) diff --git a/src/app/components/autocomplete/autocomplete.css b/src/app/components/autocomplete/autocomplete.css index d30e4e7ce97..ac715e6217a 100755 --- a/src/app/components/autocomplete/autocomplete.css +++ b/src/app/components/autocomplete/autocomplete.css @@ -42,6 +42,10 @@ overflow: hidden; } +.p-autocomplete-template-item { + min-width: 145px; +} + .p-autocomplete-multiple-container { margin: 0; padding: 0; @@ -80,6 +84,21 @@ width: 100%; } +.p-autocomplete-template-input-token { + border: 0 none; + outline: 0 none; + background-color: transparent; + margin: 0; + margin-left: .5rem; + padding: 0; + box-shadow: none; + border-radius: 0; + width: 2rem; + + flex: 1 1 auto; + display: inline-flex; +} + .p-fluid .p-autocomplete { display: flex; } @@ -97,4 +116,4 @@ .p-autocomplete-clearable { position: relative; -} \ No newline at end of file +} diff --git a/src/app/components/autocomplete/autocomplete.spec.ts b/src/app/components/autocomplete/autocomplete.spec.ts index 02f863bf2e3..cd13a809d29 100755 --- a/src/app/components/autocomplete/autocomplete.spec.ts +++ b/src/app/components/autocomplete/autocomplete.spec.ts @@ -11,9 +11,18 @@ import { ChevronDownIcon } from 'primeng/icons/chevrondown'; import { TimesCircleIcon } from 'primeng/icons/timescircle'; @Component({ - template: ` + template: ` + - ` + + + + Custom Text: {{ car.brand }} + + ` }) class TestAutocompleteComponent { brands: string[] = ['Audi', 'BMW', 'Fiat', 'Ford', 'Honda', 'Jaguar', 'Mercedes', 'Renault', 'Volvo', 'VW']; @@ -22,6 +31,7 @@ class TestAutocompleteComponent { filteredCars: any[]; brand: string; car: any; + car2: any; filterBrands(event) { this.filteredBrands = []; @@ -42,6 +52,12 @@ class TestAutocompleteComponent { } } } + + selectCustomCarOnComplete(event) { + this.filterBrandsWithField(event); + this.car2 = this.cars[0]; + } + deleteLastEl() { this.brands.pop(); } @@ -50,6 +66,7 @@ class TestAutocompleteComponent { describe('AutoComplete', () => { let autocomplete: AutoComplete; let autocomplete2: AutoComplete; + let autocomplete3: AutoComplete; let testComponent: TestAutocompleteComponent; let fixture: ComponentFixture; @@ -62,6 +79,7 @@ describe('AutoComplete', () => { fixture = TestBed.createComponent(TestAutocompleteComponent); autocomplete = fixture.debugElement.children[0].componentInstance; autocomplete2 = fixture.debugElement.children[2].componentInstance; + autocomplete3 = fixture.debugElement.children[3].componentInstance; testComponent = fixture.debugElement.componentInstance; }); @@ -454,6 +472,64 @@ describe('AutoComplete', () => { flush(); })); + it('should display custom selectedItem template element', fakeAsync(() => { + autocomplete3.field = 'brand'; + fixture.detectChanges(); + + autocomplete3.selectItem({ brand: 'Volvo' }); + fixture.detectChanges(); + expect(autocomplete3.value.brand).toEqual('Volvo'); + + const singleContainerElement = fixture.debugElement.queryAll(By.css('p-autoComplete'))[2].query( + By.css('.p-component.p-inputtext.p-autocomplete-template-item')); + const templateItemDiv = singleContainerElement.query(By.css('.p-autocomplete-token')); + const selectedItemSpanElement = templateItemDiv.query(By.css('span')); + + expect(selectedItemSpanElement).toBeTruthy(); + expect(selectedItemSpanElement.childNodes[0].nativeNode.data).toEqual("Custom Text: Volvo"); + })); + + it('should change value of custom selectedItem template on keyEnter', fakeAsync(() => { + autocomplete3.field = 'brand'; + autocomplete3.forceSelection = true; + fixture.detectChanges(); + + autocomplete3.selectItem({ brand: 'Volvo' }); + fixture.detectChanges(); + expect(autocomplete3.value.brand).toEqual('Volvo'); + + const inputEl = fixture.debugElement.queryAll(By.css('p-autoComplete'))[2].query( + By.css('.p-autocomplete-template-input-token')); + inputEl.nativeElement.dispatchEvent(new Event('focus')); + inputEl.nativeElement.focus(); + inputEl.nativeElement.click(); + fixture.detectChanges(); + + inputEl.nativeElement.value = 'VW'; + inputEl.nativeElement.dispatchEvent(new Event('keydown')); + inputEl.nativeElement.dispatchEvent(new Event('input')); + inputEl.nativeElement.dispatchEvent(new Event('keyup')); + tick(300); + fixture.detectChanges(); + + const firstItemEl = fixture.debugElement.queryAll(By.css('p-autoComplete'))[2].query( + By.css('li')).nativeElement; + firstItemEl.click(); + fixture.detectChanges(); + expect(autocomplete3.value.brand).toEqual('VW'); + expect(inputEl.nativeElement.value).toEqual(''); + expect(testComponent.car2).toEqual(autocomplete3.value); + + const singleContainerElement = fixture.debugElement.queryAll(By.css('p-autoComplete'))[2].query( + By.css('.p-component.p-inputtext.p-autocomplete-template-item')); + const templateItemDiv = singleContainerElement.query(By.css('.p-autocomplete-token')); + const selectedItemSpanElement = templateItemDiv.query(By.css('span')); + + expect(selectedItemSpanElement).toBeTruthy(); + expect(selectedItemSpanElement.childNodes[0].nativeNode.data).toEqual("Custom Text: VW"); + flush(); + })); + it('should change minLength', fakeAsync(() => { autocomplete.minLength = 2; fixture.detectChanges(); @@ -470,7 +546,7 @@ describe('AutoComplete', () => { tick(300); fixture.detectChanges(); - const panelEl = fixture.debugElement.query(By.css('div')); + const panelEl = fixture.debugElement.query(By.css('div:not(.p-autocomplete-template-item)')); expect(panelEl).toBeFalsy(); inputEl.nativeElement.value = 'va'; @@ -480,7 +556,7 @@ describe('AutoComplete', () => { tick(300); fixture.detectChanges(); - const updatedPanelEl = fixture.debugElement.query(By.css('div')); + const updatedPanelEl = fixture.debugElement.query(By.css('div:not(.p-autocomplete-template-item)')); expect(updatedPanelEl).toBeFalsy(); flush(); })); @@ -620,6 +696,23 @@ describe('AutoComplete', () => { flush(); })); + it('should delete selectedItem template with backspace', fakeAsync(() => { + autocomplete3.field = 'brand'; + fixture.detectChanges(); + + autocomplete3.selectItem({ brand: 'Volvo' }); + expect(autocomplete3.value.brand).toEqual('Volvo'); + fixture.detectChanges(); + + let backspaceEvent = new Event('keydown'); + Object.defineProperty(backspaceEvent, 'which', { value: 8 }); + Object.defineProperty(backspaceEvent, 'preventDefault', { value: () => {} }); + autocomplete3.onKeydown(backspaceEvent); + fixture.detectChanges(); + + expect(autocomplete3.value).toEqual(null); + })); + it('should navigate with arrow keys and select with enter', () => { fixture.detectChanges(); diff --git a/src/app/components/autocomplete/autocomplete.ts b/src/app/components/autocomplete/autocomplete.ts index 5c094530215..862b3c8e61f 100755 --- a/src/app/components/autocomplete/autocomplete.ts +++ b/src/app/components/autocomplete/autocomplete.ts @@ -57,7 +57,7 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = { +
+
+ +
+ +