diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
index b409082b4a..c87f96ffba 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter/search-facet-filter.component.ts
@@ -87,7 +87,8 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
const facetValues = Observable.combineLatest(searchOptions, this.currentPage, (options, page) => {
return { options, page }
}).switchMap(({ options, page }) => {
- return this.searchService.getFacetValuesFor(this.filterConfig, page, options).map((results) => {
+ return this.searchService.getFacetValuesFor(this.filterConfig, page, options)
+ .first((RD) => !RD.isLoading).map((results) => {
return {
values: Observable.of(results),
page: page
diff --git a/src/app/+search-page/search-filters/search-filters.component.html b/src/app/+search-page/search-filters/search-filters.component.html
index 1e5c474d65..0522c1fba0 100644
--- a/src/app/+search-page/search-filters/search-filters.component.html
+++ b/src/app/+search-page/search-filters/search-filters.component.html
@@ -1,7 +1,7 @@
{{"search.filters.head" | translate}}
{{"search.filters.reset" | translate}}
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filters.component.spec.ts b/src/app/+search-page/search-filters/search-filters.component.spec.ts
index 64e3a1d2c7..7f0d4ad748 100644
--- a/src/app/+search-page/search-filters/search-filters.component.spec.ts
+++ b/src/app/+search-page/search-filters/search-filters.component.spec.ts
@@ -24,6 +24,12 @@ describe('SearchFiltersComponent', () => {
}
/* tslint:enable:no-empty */
};
+
+ const searchFiltersStub = {
+ getSelectedValuesForFilter: (filter) =>
+ []
+ };
+
const searchConfigServiceStub = jasmine.createSpyObj('SearchConfigurationService', {
getCurrentFrontendFilters: Observable.of({})
});
@@ -35,6 +41,7 @@ describe('SearchFiltersComponent', () => {
providers: [
{ provide: SearchService, useValue: searchServiceStub },
{ provide: SearchConfigurationService, useValue: searchConfigServiceStub },
+ { provide: SearchFilterService, useValue: searchFiltersStub },
],
schemas: [NO_ERRORS_SCHEMA]
diff --git a/src/app/+search-page/search-filters/search-filters.component.ts b/src/app/+search-page/search-filters/search-filters.component.ts
index 9c2a0c94be..684f4d94fe 100644
--- a/src/app/+search-page/search-filters/search-filters.component.ts
+++ b/src/app/+search-page/search-filters/search-filters.component.ts
@@ -4,6 +4,8 @@ import { RemoteData } from '../../core/data/remote-data';
import { SearchFilterConfig } from '../search-service/search-filter-config.model';
import { Observable } from 'rxjs/Observable';
import { SearchConfigurationService } from '../search-service/search-configuration.service';
+import { isNotEmpty } from '../../shared/empty.util';
+import { SearchFilterService } from './search-filter/search-filter.service';
@Component({
selector: 'ds-search-filters',
@@ -30,10 +32,14 @@ export class SearchFiltersComponent {
* Initialize instance variables
* @param {SearchService} searchService
* @param {SearchConfigurationService} searchConfigService
+ * @param {SearchFilterService} filterService
*/
- constructor(private searchService: SearchService, private searchConfigService: SearchConfigurationService) {
- this.filters = searchService.getConfig();
- this.clearParams = searchConfigService.getCurrentFrontendFilters().map((filters) => {Object.keys(filters).forEach((f) => filters[f] = null); return filters;});
+ constructor(private searchService: SearchService, private searchConfigService: SearchConfigurationService, private filterService: SearchFilterService) {
+ this.filters = searchService.getConfig().first((RD) => !RD.isLoading);
+ this.clearParams = searchConfigService.getCurrentFrontendFilters().map((filters) => {
+ Object.keys(filters).forEach((f) => filters[f] = null);
+ return filters;
+ });
}
/**
@@ -42,4 +48,29 @@ export class SearchFiltersComponent {
getSearchLink() {
return this.searchService.getSearchLink();
}
+
+ /**
+ * Check if a given filter is supposed to be shown or not
+ * @param {SearchFilterConfig} filter The filter to check for
+ * @returns {Observable} Emits true whenever a given filter config should be shown
+ */
+ isActive(filter: SearchFilterConfig): Observable {
+ // console.log(filter.name);
+ return this.filterService.getSelectedValuesForFilter(filter)
+ .flatMap((isActive) => {
+ if (isNotEmpty(isActive)) {
+ return Observable.of(true);
+ } else {
+ return this.searchConfigService.searchOptions
+ .switchMap((options) => {
+ return this.searchService.getFacetValuesFor(filter, 1, options)
+ .filter((RD) => !RD.isLoading)
+ .map((valuesRD) => {
+ return valuesRD.payload.totalElements > 0
+ })
+ }
+ )
+ }
+ }).startWith(true);
+ }
}
diff --git a/src/app/+search-page/search-labels/search-labels.component.html b/src/app/+search-page/search-labels/search-labels.component.html
index 5113e764ff..61a5618dad 100644
--- a/src/app/+search-page/search-labels/search-labels.component.html
+++ b/src/app/+search-page/search-labels/search-labels.component.html
@@ -1,12 +1,13 @@
-
+
diff --git a/src/app/+search-page/search-labels/search-labels.component.scss b/src/app/+search-page/search-labels/search-labels.component.scss
new file mode 100644
index 0000000000..c48cd57304
--- /dev/null
+++ b/src/app/+search-page/search-labels/search-labels.component.scss
@@ -0,0 +1,3 @@
+:host {
+ line-height: 1;
+}
\ No newline at end of file
diff --git a/src/app/+search-page/search-labels/search-labels.component.ts b/src/app/+search-page/search-labels/search-labels.component.ts
index f5215d7997..61482f8d8a 100644
--- a/src/app/+search-page/search-labels/search-labels.component.ts
+++ b/src/app/+search-page/search-labels/search-labels.component.ts
@@ -8,6 +8,7 @@ import { SearchConfigurationService } from '../search-service/search-configurati
@Component({
selector: 'ds-search-labels',
+ styleUrls: ['./search-labels.component.scss'],
templateUrl: './search-labels.component.html',
})
diff --git a/src/app/+search-page/search-service/search-configuration.service.ts b/src/app/+search-page/search-service/search-configuration.service.ts
index 95c4c60d65..8ad0b684ad 100644
--- a/src/app/+search-page/search-service/search-configuration.service.ts
+++ b/src/app/+search-page/search-service/search-configuration.service.ts
@@ -16,24 +16,55 @@ import { Subscription } from 'rxjs/Subscription';
*/
@Injectable()
export class SearchConfigurationService implements OnDestroy {
+ /**
+ * Default pagination settings
+ */
private defaultPagination = Object.assign(new PaginationComponentOptions(), {
id: 'search-page-configuration',
pageSize: 10,
currentPage: 1
});
+ /**
+ * Default sort settings
+ */
private defaultSort = new SortOptions('score', SortDirection.DESC);
+ /**
+ * Default scope setting
+ */
private defaultScope = '';
+ /**
+ * Default query setting
+ */
private defaultQuery = '';
- private _defaults;
+ /**
+ * Emits the current default values
+ */
+ private _defaults: Observable
>;
+ /**
+ * Emits the current search options
+ */
public searchOptions: BehaviorSubject;
+
+ /**
+ * Emits the current search options including pagination and sort
+ */
public paginatedSearchOptions: BehaviorSubject;
+
+ /**
+ * List of subscriptions to unsubscribe from on destroy
+ */
private subs: Subscription[] = new Array();
+ /**
+ * Initialize the search options
+ * @param {RouteService} routeService
+ * @param {ActivatedRoute} route
+ */
constructor(private routeService: RouteService,
private route: ActivatedRoute) {
this.defaults.first().subscribe((defRD) => {
@@ -128,6 +159,11 @@ export class SearchConfigurationService implements OnDestroy {
return this.routeService.getQueryParamsWithPrefix('f.');
}
+ /**
+ * Sets up a subscription to all necessary parameters to make sure the searchOptions emits a new value every time they update
+ * @param {SearchOptions} defaults Default values for when no parameters are available
+ * @returns {Subscription} The subscription to unsubscribe from
+ */
subscribeToSearchOptions(defaults: SearchOptions): Subscription {
return Observable.merge(
this.getScopePart(defaults.scope),
@@ -140,6 +176,11 @@ export class SearchConfigurationService implements OnDestroy {
});
}
+ /**
+ * Sets up a subscription to all necessary parameters to make sure the paginatedSearchOptions emits a new value every time they update
+ * @param {PaginatedSearchOptions} defaults Default values for when no parameters are available
+ * @returns {Subscription} The subscription to unsubscribe from
+ */
subscribeToPaginatedSearchOptions(defaults: PaginatedSearchOptions): Subscription {
return Observable.merge(
this.getPaginationPart(defaults.pagination),
@@ -170,12 +211,18 @@ export class SearchConfigurationService implements OnDestroy {
return this._defaults;
}
+ /**
+ * Make sure to unsubscribe from all existing subscription to prevent memory leaks
+ */
ngOnDestroy(): void {
this.subs.forEach((sub) => {
sub.unsubscribe();
});
}
+ /**
+ * @returns {Observable} Emits the current scope's identifier
+ */
private getScopePart(defaultScope: string): Observable {
return this.getCurrentScope(defaultScope).map((scope) => {
return { scope }
@@ -183,7 +230,7 @@ export class SearchConfigurationService implements OnDestroy {
}
/**
- * @returns {Observable} Emits the current query string
+ * @returns {Observable} Emits the current query string as a partial SearchOptions object
*/
private getQueryPart(defaultQuery: string): Observable {
return this.getCurrentQuery(defaultQuery).map((query) => {
@@ -192,7 +239,7 @@ export class SearchConfigurationService implements OnDestroy {
}
/**
- * @returns {Observable} Emits the current pagination settings
+ * @returns {Observable} Emits the current pagination settings as a partial SearchOptions object
*/
private getPaginationPart(defaultPagination: PaginationComponentOptions): Observable {
return this.getCurrentPagination(defaultPagination).map((pagination) => {
@@ -201,7 +248,7 @@ export class SearchConfigurationService implements OnDestroy {
}
/**
- * @returns {Observable} Emits the current sorting settings
+ * @returns {Observable} Emits the current sorting settings as a partial SearchOptions object
*/
private getSortPart(defaultSort: SortOptions): Observable {
return this.getCurrentSort(defaultSort).map((sort) => {
@@ -210,7 +257,7 @@ export class SearchConfigurationService implements OnDestroy {
}
/**
- * @returns {Observable} Emits the current active filters with their values as they are sent to the backend
+ * @returns {Observable} Emits the current active filters as a partial SearchOptions object
*/
private getFiltersPart(): Observable {
return this.getCurrentFilters().map((filters) => {
diff --git a/src/app/core/data/paginated-list.ts b/src/app/core/data/paginated-list.ts
index 21cc13f3fa..07d53739d0 100644
--- a/src/app/core/data/paginated-list.ts
+++ b/src/app/core/data/paginated-list.ts
@@ -8,7 +8,7 @@ export class PaginatedList {
}
get elementsPerPage(): number {
- if (hasValue(this.pageInfo)) {
+ if (hasValue(this.pageInfo) && hasValue(this.pageInfo.elementsPerPage)) {
return this.pageInfo.elementsPerPage;
}
return this.page.length;
@@ -19,7 +19,7 @@ export class PaginatedList {
}
get totalElements(): number {
- if (hasValue(this.pageInfo)) {
+ if (hasValue(this.pageInfo) && hasValue(this.pageInfo.totalElements)) {
return this.pageInfo.totalElements;
}
return this.page.length;
@@ -30,7 +30,7 @@ export class PaginatedList {
}
get totalPages(): number {
- if (hasValue(this.pageInfo)) {
+ if (hasValue(this.pageInfo) && hasValue(this.pageInfo.totalPages)) {
return this.pageInfo.totalPages;
}
return 1;
@@ -41,7 +41,7 @@ export class PaginatedList {
}
get currentPage(): number {
- if (hasValue(this.pageInfo)) {
+ if (hasValue(this.pageInfo) && hasValue(this.pageInfo.currentPage)) {
return this.pageInfo.currentPage;
}
return 1;
diff --git a/src/app/core/data/registry-metadatafields-response-parsing.service.ts b/src/app/core/data/registry-metadatafields-response-parsing.service.ts
index 2620916070..1fe8b1e15f 100644
--- a/src/app/core/data/registry-metadatafields-response-parsing.service.ts
+++ b/src/app/core/data/registry-metadatafields-response-parsing.service.ts
@@ -1,15 +1,13 @@
import {
- RegistryMetadatafieldsSuccessResponse, RegistryMetadataschemasSuccessResponse,
+ RegistryMetadatafieldsSuccessResponse,
RestResponse
} from '../cache/response-cache.models';
import { DSpaceRESTV2Response } from '../dspace-rest-v2/dspace-rest-v2-response.model';
import { RestRequest } from './request.models';
import { ResponseParsingService } from './parsing.service';
-import { RegistryMetadataschemasResponse } from '../registry/registry-metadataschemas-response.model';
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
import { DSOResponseParsingService } from './dso-response-parsing.service';
import { Injectable } from '@angular/core';
-import { forEach } from '@angular/router/src/utils/collection';
import { RegistryMetadatafieldsResponse } from '../registry/registry-metadatafields-response.model';
@Injectable()
diff --git a/src/app/shared/input-suggestions/input-suggestions.component.html b/src/app/shared/input-suggestions/input-suggestions.component.html
index 02ef38dea0..bbe090dac0 100644
--- a/src/app/shared/input-suggestions/input-suggestions.component.html
+++ b/src/app/shared/input-suggestions/input-suggestions.component.html
@@ -5,7 +5,7 @@
(dsClickOutside)="close()">
diff --git a/src/app/shared/input-suggestions/input-suggestions.component.ts b/src/app/shared/input-suggestions/input-suggestions.component.ts
index f95fd4611d..eb28583eaa 100644
--- a/src/app/shared/input-suggestions/input-suggestions.component.ts
+++ b/src/app/shared/input-suggestions/input-suggestions.component.ts
@@ -80,6 +80,11 @@ export class InputSuggestionsComponent {
*/
selectedIndex = -1;
+ /**
+ * True when the dropdown should not reopen
+ */
+ blockReopen = false;
+
/**
* Reference to the input field component
*/
@@ -162,13 +167,25 @@ export class InputSuggestionsComponent {
}
/**
- * Make sure that if a suggestion is clicked, the suggestions dropdown closes and the focus moves to the input field
+ * Make sure that if a suggestion is clicked, the suggestions dropdown closes, does not reopen and the focus moves to the input field
*/
onClickSuggestion(data) {
this.clickSuggestion.emit(data);
this.close();
+ this.blockReopen = true;
this.queryInput.nativeElement.focus();
return false;
}
+ /**
+ * Finds new suggestions when necessary
+ * @param data The query value to emit
+ */
+ find(data) {
+ if (!this.blockReopen) {
+ this.findSuggestions.emit(data);
+ }
+ this.blockReopen = false;
+ }
+
}
diff --git a/src/app/shared/search-form/search-form.component.ts b/src/app/shared/search-form/search-form.component.ts
index a556e4c036..21a90daed4 100644
--- a/src/app/shared/search-form/search-form.component.ts
+++ b/src/app/shared/search-form/search-form.component.ts
@@ -1,7 +1,7 @@
import { Component, Input } from '@angular/core';
import { DSpaceObject } from '../../core/shared/dspace-object.model';
import { Router } from '@angular/router';
-import { isNotEmpty, hasValue, isEmpty, hasNoValue } from '../empty.util';
+import { hasValue, isNotEmpty } from '../empty.util';
import { QueryParamsHandling } from '@angular/router/src/config';
/**