From 6d64326238745cd43677d445934daf3d8424ba8d Mon Sep 17 00:00:00 2001 From: lotte Date: Tue, 19 Mar 2019 16:22:16 +0100 Subject: [PATCH] Added debounce, fixed error handling for search results, fixed bug in paginated lists --- .../+search-page/search-service/search.service.ts | 4 ++-- src/app/core/data/paginated-list.ts | 5 ++++- .../dso-selector/dso-selector.component.spec.ts | 14 +++++++++++--- .../dso-selector/dso-selector.component.ts | 9 +++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/app/+search-page/search-service/search.service.ts b/src/app/+search-page/search-service/search.service.ts index 275b0b3340d..2c0f1f4e55d 100644 --- a/src/app/+search-page/search-service/search.service.ts +++ b/src/app/+search-page/search-service/search.service.ts @@ -23,7 +23,7 @@ import { DSpaceObject } from '../../core/shared/dspace-object.model'; import { GenericConstructor } from '../../core/shared/generic-constructor'; import { HALEndpointService } from '../../core/shared/hal-endpoint.service'; import { - configureRequest, + configureRequest, filterSuccessfulResponses, getResponseFromEntry, getSucceededRemoteData } from '../../core/shared/operators'; @@ -104,7 +104,7 @@ export class SearchService implements OnDestroy { // get search results from response cache const sqrObs: Observable = requestEntryObs.pipe( - getResponseFromEntry(), + filterSuccessfulResponses(), map((response: SearchSuccessResponse) => response.results) ); diff --git a/src/app/core/data/paginated-list.ts b/src/app/core/data/paginated-list.ts index 8efdccd75d5..faecd231bc9 100644 --- a/src/app/core/data/paginated-list.ts +++ b/src/app/core/data/paginated-list.ts @@ -1,5 +1,5 @@ import { PageInfo } from '../shared/page-info.model'; -import { hasValue } from '../../shared/empty.util'; +import { hasNoValue, hasValue } from '../../shared/empty.util'; export class PaginatedList { @@ -22,6 +22,9 @@ export class PaginatedList { if (hasValue(this.pageInfo) && hasValue(this.pageInfo.totalElements)) { return this.pageInfo.totalElements; } + if (hasNoValue(this.page)) { + return 0; + } return this.page.length; } diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts index 0386276be7c..04111a4ea6e 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.spec.ts @@ -1,4 +1,4 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { TranslateModule } from '@ngx-translate/core'; import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; import { DSOSelectorComponent } from './dso-selector.component'; @@ -21,7 +21,12 @@ describe('DSOSelectorComponent', () => { const type = DSpaceObjectType.ITEM; const searchResult = new ItemSearchResult(); const item = new Item(); - item.metadata = { 'dc.title': [Object.assign(new MetadataValue(), { value: 'Item title', language: undefined })] }; + item.metadata = { + 'dc.title': [Object.assign(new MetadataValue(), { + value: 'Item title', + language: undefined + })] + }; searchResult.dspaceObject = item; searchResult.hitHighlights = {}; const searchService = jasmine.createSpyObj('searchService', { @@ -46,6 +51,7 @@ describe('DSOSelectorComponent', () => { debugElement = fixture.debugElement; component.currentDSOId = currentDSOId; component.type = type; + fixture.detectChanges(); }); @@ -59,7 +65,9 @@ describe('DSOSelectorComponent', () => { dsoType: type, pagination: (component as any).defaultPagination }); + expect(searchService.search).toHaveBeenCalledWith(searchOptions); }); -}); +}) +; diff --git a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts index 7bb9bfac28d..04501e49232 100644 --- a/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts +++ b/src/app/shared/dso-selector/dso-selector/dso-selector.component.ts @@ -1,5 +1,4 @@ import { - AfterViewInit, Component, ElementRef, EventEmitter, @@ -12,7 +11,7 @@ import { import { FormControl } from '@angular/forms'; import { Observable } from 'rxjs'; -import { map, startWith, switchMap, take } from 'rxjs/operators'; +import { debounceTime, startWith, switchMap } from 'rxjs/operators'; import { SearchService } from '../../../+search-page/search-service/search.service'; import { PaginatedSearchOptions } from '../../../+search-page/paginated-search-options.model'; import { DSpaceObjectType } from '../../../core/shared/dspace-object-type.model'; @@ -68,6 +67,11 @@ export class DSOSelectorComponent implements OnInit { */ @ViewChildren('listEntryElement') listElements: QueryList; + /** + * Time to wait before sending a search request to the server when a user types something + */ + debounceTime = 500; + constructor(private searchService: SearchService) { } @@ -79,6 +83,7 @@ export class DSOSelectorComponent implements OnInit { this.input.setValue(this.currentDSOId); this.listEntries$ = this.input.valueChanges .pipe( + debounceTime(this.debounceTime), startWith(this.currentDSOId), switchMap((query) => { return this.searchService.search(