diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts index ca73c782d282523f6ae32f0ef50fa9ec872d217f..0cdada208ef8341a5b0c15821c1f0992074be7eb 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts @@ -30,21 +30,11 @@ import { createEmptyStateResource, createStateResource, } from '@alfa-client/tech-shared'; -import { - dispatchEventFromFixture, - getElementFromFixture, - mock, - useFromMock, -} from '@alfa-client/test-utils'; +import { dispatchEventFromFixture, getElementFromFixture, mock, useFromMock } from '@alfa-client/test-utils'; import { SpinnerComponent } from '@alfa-client/ui'; import { VorgangHeaderLinkRel, VorgangListService } from '@alfa-client/vorgang-shared'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { - ReactiveFormsModule, - UntypedFormBuilder, - UntypedFormControl, - UntypedFormGroup, -} from '@angular/forms'; +import { ReactiveFormsModule, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButton } from '@angular/material/button'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -224,21 +214,15 @@ describe('VorgangSearchComponent', () => { const result = component.buildSearchResultPreviewLabel(vorgangList); - expect(result).toBe( - '10 Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen', - ); + expect(result).toBe('10 Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen'); }); it('should return label for one search result', () => { - const vorgangList = createStateResource( - createVorgangListResourceWithResource([createVorgangResource()]), - ); + const vorgangList = createStateResource(createVorgangListResourceWithResource([createVorgangResource()])); const result = component.buildSearchResultPreviewLabel(vorgangList); - expect(result).toBe( - 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen', - ); + expect(result).toBe('Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen'); }); it('should return empty string', () => { @@ -298,6 +282,17 @@ describe('VorgangSearchComponent', () => { }); }); + describe('onKeydownHandler', () => { + it('should call formService setLastKeyPressed with key', () => { + const setLastKeyPressedSpy = jest.spyOn(VorgangSearchFormService.prototype, 'setLastKeyPressed'); + const keyboardEvent: KeyboardEvent = new KeyboardEvent('keydown', { key: 'Enter' }); + + component.onKeydownHandler(keyboardEvent); + + expect(setLastKeyPressedSpy).toHaveBeenCalledWith('Enter'); + }); + }); + describe('submit', () => { it('should not navigate to search if search field is empty', () => { const submitSpy = jest.spyOn(NavigationService.prototype, 'search'); diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts index 7857c502c95a7b38bed14c9a85ef50d8a748a68a..e6172d545e4cd6c7f8f62f7562f75e3c7d219022 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts @@ -21,27 +21,9 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - EMPTY_STRING, - StateResource, - getEmbeddedResources, - isNotNil, -} from '@alfa-client/tech-shared'; -import { - VorgangHeaderLinkRel, - VorgangListLinkRel, - VorgangListResource, -} from '@alfa-client/vorgang-shared'; -import { - Component, - ElementRef, - EventEmitter, - Input, - OnDestroy, - OnInit, - Output, - ViewChild, -} from '@angular/core'; +import { EMPTY_STRING, StateResource, getEmbeddedResources, isNotNil } from '@alfa-client/tech-shared'; +import { VorgangHeaderLinkRel, VorgangListLinkRel, VorgangListResource } from '@alfa-client/vorgang-shared'; +import { Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { MatAutocomplete } from '@angular/material/autocomplete'; import { MatButton } from '@angular/material/button'; import { Event, NavigationEnd, Router } from '@angular/router'; @@ -56,9 +38,7 @@ import { VorgangSearchFormService } from './vorgang-search.formservice'; providers: [VorgangSearchFormService], }) export class VorgangSearchComponent implements OnInit, OnDestroy { - @Input() set vorgangSearchPreviewList( - vorgangListStateResource: StateResource<VorgangListResource>, - ) { + @Input() set vorgangSearchPreviewList(vorgangListStateResource: StateResource<VorgangListResource>) { this.vorgangListPreview = vorgangListStateResource; this.searchResultPreviewLabel = this.buildSearchResultPreviewLabel(vorgangListStateResource); } @@ -93,6 +73,11 @@ export class VorgangSearchComponent implements OnInit, OnDestroy { }); } + @HostListener('keydown', ['$event']) + onKeydownHandler(e: KeyboardEvent): void { + this.formService.setLastKeyPressed(e.key); + } + submit(): void { this.previouslyEnteredSearchValue = this.formService.getValue(); this.formService.submit(); @@ -113,15 +98,9 @@ export class VorgangSearchComponent implements OnInit, OnDestroy { } } - buildSearchResultPreviewLabel( - vorgangListStateResource: StateResource<VorgangListResource>, - ): string { - const previewListLength = getEmbeddedResources( - vorgangListStateResource, - this.vorgangListLinkRel.VORGANG_HEADER_LIST, - )?.length; - if (previewListLength === 1) - return 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen'; + buildSearchResultPreviewLabel(vorgangListStateResource: StateResource<VorgangListResource>): string { + const previewListLength = getEmbeddedResources(vorgangListStateResource, this.vorgangListLinkRel.VORGANG_HEADER_LIST)?.length; + if (previewListLength === 1) return 'Ein Vorschlag wird angezeigt, nutze Pfeiltaste nach unten, um den zu erreichen'; if (previewListLength > 1) return `${previewListLength} Vorschläge werden angezeigt, nutze Pfeiltaste nach unten, um diese zu erreichen`; return EMPTY_STRING; diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts index 93444238b4cf52ce3acf44aa56f7563366c80b89..3e50dab989a308dc773e7aaea7018cd0e2312238 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.spec.ts @@ -72,15 +72,6 @@ describe('VorgangSearchFormService', () => { }); describe('subscribeToValueChanges', () => { - it('should set searchForPreview to true', () => { - const setSearchForPreview = jest.spyOn(formService, 'setSearchForPreview'); - - formService.subscribeToValueChanges(); - formService.form.controls[formService.SEARCH_FIELD].patchValue(faker.word.sample()); - - expect(setSearchForPreview).toHaveBeenCalledWith(true); - }); - it('should call setHasSearchString after debounce time', fakeAsync(() => { const value = faker.word.sample(); const setHasSearchString = jest.spyOn(formService, 'setHasSearchString'); @@ -102,6 +93,16 @@ describe('VorgangSearchFormService', () => { expect(handleValueChanges).toHaveBeenCalledWith(value); })); + + it('should call not call handleValueChange after if lastKeyPressed is Enter', fakeAsync(() => { + const handleValueChanges = jest.spyOn(formService, 'handleValueChanges'); + formService.setLastKeyPressed('Enter'); + + formService.subscribeToValueChanges(); + tick(300); + + expect(handleValueChanges).not.toHaveBeenCalled(); + })); }); describe('handleValueChanges', () => { @@ -239,16 +240,6 @@ describe('VorgangSearchFormService', () => { expect(navigationService.search).toHaveBeenCalledWith(SEARCH_STRING); }); - - it('should set searchForPreview to false', () => { - const setSearchForPreview = jest.spyOn(formService, 'setSearchForPreview'); - formService.hasSearchString = true; - getSearchFormControl().patchValue(SEARCH_STRING); - - formService.submit(); - - expect(setSearchForPreview).toHaveBeenCalledWith(false); - }); }); describe('clear button', () => { diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts index 1a21b3cd61abb182521a765f629db4a386e654b6..fbbefc0fad156294062641d2fcb3e9e0729f13fb 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.formservice.ts @@ -28,7 +28,7 @@ import { Injectable, OnDestroy } from '@angular/core'; import { FormGroup, UntypedFormBuilder, UntypedFormControl } from '@angular/forms'; import { Params } from '@angular/router'; import { isEmpty } from 'lodash-es'; -import { Observable, Subscription } from 'rxjs'; +import { BehaviorSubject, combineLatest, Observable, Subscription } from 'rxjs'; import { debounceTime, distinctUntilChanged, first, tap } from 'rxjs/operators'; @Injectable() @@ -44,7 +44,7 @@ export class VorgangSearchFormService implements OnDestroy { public lastSearchString: string; public hasSearchString: boolean = false; - private searchForPreview: boolean = false; + private lastKeyPressed: BehaviorSubject<string> = new BehaviorSubject<string>(EMPTY_STRING); constructor( private formBuilder: UntypedFormBuilder, @@ -68,18 +68,16 @@ export class VorgangSearchFormService implements OnDestroy { } subscribeToValueChanges(): void { - this.fromControlSubscription = this.getSearchFormControl() - .valueChanges.pipe( + this.fromControlSubscription = combineLatest( + this.lastKeyPressed.asObservable(), + this.getSearchFormControl().valueChanges.pipe( distinctUntilChanged(), - tap(() => this.setSearchForPreview(true)), debounceTime(300), tap((value) => this.setHasSearchString(value)), - ) - .subscribe((value) => this.handleValueChanges(value)); - } - - setSearchForPreview(value: boolean): void { - this.searchForPreview = value; + ), + ).subscribe(([lastKeyPressed, value]) => { + if (lastKeyPressed !== 'Enter') this.handleValueChanges(value); + }); } setHasSearchString(value: string): void { @@ -96,7 +94,7 @@ export class VorgangSearchFormService implements OnDestroy { } shouldSearchForPreview(value: string): boolean { - return this.searchForPreview && this.isSearchInputNotPristine() && hasMinLength(value, this.PREVIEW_SEARCH_STRING_MIN_LENGTH); + return this.isSearchInputNotPristine() && hasMinLength(value, this.PREVIEW_SEARCH_STRING_MIN_LENGTH); } isSearchInputNotPristine(): boolean { @@ -120,7 +118,6 @@ export class VorgangSearchFormService implements OnDestroy { submit(): void { if (this.hasSearchString) { this.navigationService.search(this.getValue()); - this.setSearchForPreview(false); } } @@ -172,4 +169,8 @@ export class VorgangSearchFormService implements OnDestroy { public getValueChanges(): Observable<string> { return this.getSearchFormControl().valueChanges; } + + public setLastKeyPressed(key: string): void { + this.lastKeyPressed.next(key); + } }