diff --git a/projects/aca-content/src/lib/components/search/search-save/dialog/save-search-dialog.component.spec.ts b/projects/aca-content/src/lib/components/search/search-save/dialog/save-search-dialog.component.spec.ts index 7a1782133..a119b868d 100644 --- a/projects/aca-content/src/lib/components/search/search-save/dialog/save-search-dialog.component.spec.ts +++ b/projects/aca-content/src/lib/components/search/search-save/dialog/save-search-dialog.component.spec.ts @@ -89,9 +89,24 @@ describe('SaveSearchDialogComponent', () => { expect(notificationService.showError).toHaveBeenCalledWith('APP.BROWSE.SEARCH.SAVE_SEARCH.SAVE_ERROR'); })); + it('should call getSavedSearches only once when user types multiple times within the debounce window', fakeAsync(() => { + const getSavedSearchesSpy = spyOn(savedSearchesService, 'getSavedSearches').and.callThrough(); + const nameControl = component.form.controls['name']; + + nameControl.setValue('a'); + tick(100); + nameControl.setValue('ab'); + tick(100); + nameControl.setValue('abc'); + tick(300); + + expect(getSavedSearchesSpy).toHaveBeenCalledTimes(1); + })); + function setFormValuesAndSubmit() { component.form.controls['name'].setValue('ABCDEF'); component.form.controls['description'].setValue('TEST'); + tick(300); submitButton.click(); tick(); expect(savedSearchesService.saveSearch).toHaveBeenCalledWith({ diff --git a/projects/aca-content/src/lib/components/search/search-save/dialog/unique-search-name-validator.ts b/projects/aca-content/src/lib/components/search/search-save/dialog/unique-search-name-validator.ts index 55bc95e47..2e290d754 100644 --- a/projects/aca-content/src/lib/components/search/search-save/dialog/unique-search-name-validator.ts +++ b/projects/aca-content/src/lib/components/search/search-save/dialog/unique-search-name-validator.ts @@ -24,15 +24,18 @@ import { Injectable, inject } from '@angular/core'; import { AbstractControl, AsyncValidator, ValidationErrors } from '@angular/forms'; -import { catchError, map, Observable, of } from 'rxjs'; +import { catchError, map, Observable, of, switchMap, timer } from 'rxjs'; import { SavedSearchesContextService } from '../../../../services/saved-searches-context.service'; +const VALIDATION_DEBOUNCE_TIME = 300; + @Injectable({ providedIn: 'root' }) export class UniqueSearchNameValidator implements AsyncValidator { private readonly savedSearchesService = inject(SavedSearchesContextService); validate(control: AbstractControl): Observable { - return this.savedSearchesService.getSavedSearches().pipe( + return timer(VALIDATION_DEBOUNCE_TIME).pipe( + switchMap(() => this.savedSearchesService.getSavedSearches()), map((searches) => searches.some((search) => search.name === control.value && control.dirty) ? { message: 'APP.BROWSE.SEARCH.SAVE_SEARCH.SEARCH_NAME_NOT_UNIQUE_ERROR' }