mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
latest fixes for search page
This commit is contained in:
@@ -3,6 +3,7 @@ import { SearchFilterConfig } from '../../search-service/search-filter-config.mo
|
|||||||
import { SearchFilterService } from './search-filter.service';
|
import { SearchFilterService } from './search-filter.service';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { slide } from '../../../shared/animations/slide';
|
import { slide } from '../../../shared/animations/slide';
|
||||||
|
import { isNotEmpty } from '../../../shared/empty.util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This component renders a simple item page.
|
* This component renders a simple item page.
|
||||||
@@ -25,8 +26,8 @@ export class SearchFilterComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.filterService.isFilterActive(this.filter.paramName).first().subscribe((isActive) => {
|
this.getSelectedValues().first().subscribe((isActive) => {
|
||||||
if (this.filter.isOpenByDefault || isActive) {
|
if (this.filter.isOpenByDefault || isNotEmpty(isActive)) {
|
||||||
this.initialExpand();
|
this.initialExpand();
|
||||||
} else {
|
} else {
|
||||||
this.initialCollapse();
|
this.initialCollapse();
|
||||||
|
@@ -11,7 +11,6 @@ import { SearchFiltersState } from './search-filter.reducer';
|
|||||||
import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
|
import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
|
||||||
import { FilterType } from '../../search-service/filter-type.model';
|
import { FilterType } from '../../search-service/filter-type.model';
|
||||||
import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub';
|
import { ActivatedRouteStub } from '../../../shared/testing/active-router-stub';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
|
||||||
|
|
||||||
describe('SearchFilterService', () => {
|
describe('SearchFilterService', () => {
|
||||||
let service: SearchFilterService;
|
let service: SearchFilterService;
|
||||||
|
@@ -21,7 +21,6 @@ import { PaginationComponentOptions } from '../../../shared/pagination/paginatio
|
|||||||
import { SearchOptions } from '../../search-options.model';
|
import { SearchOptions } from '../../search-options.model';
|
||||||
import { PaginatedSearchOptions } from '../../paginated-search-options.model';
|
import { PaginatedSearchOptions } from '../../paginated-search-options.model';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute, Params } from '@angular/router';
|
||||||
import { FilterLabel } from '../../search-service/filter-label.model';
|
|
||||||
|
|
||||||
const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
|
const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
|
||||||
|
|
||||||
@@ -85,8 +84,8 @@ export class SearchFilterService {
|
|||||||
if (key.endsWith('.min') || key.endsWith('.max')) {
|
if (key.endsWith('.min') || key.endsWith('.max')) {
|
||||||
const realKey = key.slice(0, -4);
|
const realKey = key.slice(0, -4);
|
||||||
if (isEmpty(params[realKey])) {
|
if (isEmpty(params[realKey])) {
|
||||||
const min = filterParams[realKey + '.min'][0] || '*';
|
const min = filterParams[realKey + '.min'] ? filterParams[realKey + '.min'][0] : '*';
|
||||||
const max = filterParams[realKey + '.max'][0] || '*';
|
const max = filterParams[realKey + '.max'] ? filterParams[realKey + '.max'][0] : '*';
|
||||||
params[realKey] = ['[' + min + ' TO ' + max + ']'];
|
params[realKey] = ['[' + min + ' TO ' + max + ']'];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -99,21 +98,7 @@ export class SearchFilterService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentFilterLabels(): Observable<FilterLabel[]> {
|
getCurrentFrontendFilters(): Observable<Params> {
|
||||||
return this.getCurrentFilters().pipe(
|
|
||||||
map((params: Params) => {
|
|
||||||
const filterLabels: FilterLabel[] = [];
|
|
||||||
Object.keys(params).forEach((key) => {
|
|
||||||
params[key].forEach((p: string) => {
|
|
||||||
filterLabels.push(new FilterLabel(p, key));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return filterLabels;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentFrontendFilters(): Observable<any> {
|
|
||||||
return this.routeService.getQueryParamsWithPrefix('f.');
|
return this.routeService.getQueryParamsWithPrefix('f.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +150,14 @@ export class SearchFilterService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable<string[]> {
|
getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable<string[]> {
|
||||||
return this.routeService.getQueryParameterValues(filterConfig.paramName);
|
const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName);
|
||||||
|
const prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').map((params: Params) => [].concat(...Object.values(params)));
|
||||||
|
return Observable.combineLatest(values$, prefixValues$, (values, prefixValues) => {
|
||||||
|
if (isNotEmpty(values)) {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
return prefixValues;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
isCollapsed(filterName: string): Observable<boolean> {
|
isCollapsed(filterName: string): Observable<boolean> {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { isPlatformBrowser } from '@angular/common';
|
import { isPlatformBrowser } from '@angular/common';
|
||||||
import { Component, Inject, OnInit, PLATFORM_ID } from '@angular/core';
|
import { Component, Inject, OnChanges, OnInit, PLATFORM_ID } from '@angular/core';
|
||||||
import { FilterType } from '../../../search-service/filter-type.model';
|
import { FilterType } from '../../../search-service/filter-type.model';
|
||||||
import { renderFacetFor } from '../search-filter-type-decorator';
|
import { renderFacetFor } from '../search-filter-type-decorator';
|
||||||
import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component';
|
import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component';
|
||||||
@@ -51,6 +51,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
getAddParams(value: string) {
|
getAddParams(value: string) {
|
||||||
const parts = value.split(rangeDelimiter);
|
const parts = value.split(rangeDelimiter);
|
||||||
const min = parts.length > 1 ? parts[0].trim() : value;
|
const min = parts.length > 1 ? parts[0].trim() : value;
|
||||||
@@ -70,12 +72,27 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRemoveMaxParam() {
|
||||||
|
return {
|
||||||
|
[this.filterConfig.paramName + maxSuffix]: null,
|
||||||
|
page: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getRemoveMinParam() {
|
||||||
|
return {
|
||||||
|
[this.filterConfig.paramName + minSuffix]: null,
|
||||||
|
page: 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
|
const newMin = this.range[0] !== this.min ? [this.range[0]] : null;
|
||||||
|
const newMax = this.range[1] !== this.max ? [this.range[1]] : null;
|
||||||
this.router.navigate([this.getSearchLink()], {
|
this.router.navigate([this.getSearchLink()], {
|
||||||
queryParams:
|
queryParams:
|
||||||
{
|
{
|
||||||
[this.filterConfig.paramName + minSuffix]: [this.range[0]],
|
[this.filterConfig.paramName + minSuffix]: newMin,
|
||||||
[this.filterConfig.paramName + maxSuffix]: [this.range[1]]
|
[this.filterConfig.paramName + maxSuffix]: newMax
|
||||||
},
|
},
|
||||||
queryParamsHandling: 'merge'
|
queryParamsHandling: 'merge'
|
||||||
});
|
});
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="labels col-sm-9 offset-sm-3">
|
<div class="labels col-sm-9 offset-sm-3">
|
||||||
<a *ngFor="let label of (appliedFilters | async)" class="badge badge-primary mr-1"
|
<ng-container *ngFor="let key of ((appliedFilters | async) | dsObjectKeys)">
|
||||||
[routerLink]="getSearchLink()"
|
<a *ngFor="let values of (appliedFilters | async)[key]" class="badge badge-primary mr-1"
|
||||||
[queryParams]="(getRemoveParams(label) | async)" queryParamsHandling="merge">
|
[routerLink]="getSearchLink()"
|
||||||
{{label.value}}
|
[queryParams]="(getRemoveParams(key, values) | async)" queryParamsHandling="merge">
|
||||||
<span> ×</span>
|
{{values}}
|
||||||
</a>
|
<span> ×</span>
|
||||||
</div>
|
</a>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -2,9 +2,9 @@ import { Component } from '@angular/core';
|
|||||||
import { SearchService } from '../search-service/search.service';
|
import { SearchService } from '../search-service/search.service';
|
||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
import { Params } from '@angular/router';
|
import { Params } from '@angular/router';
|
||||||
import { FilterLabel } from '../search-service/filter-label.model';
|
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { SearchFilterService } from '../search-filters/search-filter/search-filter.service';
|
import { SearchFilterService } from '../search-filters/search-filter/search-filter.service';
|
||||||
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-search-labels',
|
selector: 'ds-search-labels',
|
||||||
@@ -12,27 +12,23 @@ import { SearchFilterService } from '../search-filters/search-filter/search-filt
|
|||||||
})
|
})
|
||||||
|
|
||||||
export class SearchLabelsComponent {
|
export class SearchLabelsComponent {
|
||||||
appliedFilters: Observable<FilterLabel[]>;
|
appliedFilters: Observable<Params>;
|
||||||
|
|
||||||
constructor(private searchService: SearchService, private filterService: SearchFilterService) {
|
constructor(private searchService: SearchService, private filterService: SearchFilterService) {
|
||||||
this.appliedFilters = this.filterService.getCurrentFilterLabels();
|
this.appliedFilters = this.filterService.getCurrentFrontendFilters();
|
||||||
}
|
}
|
||||||
|
|
||||||
getRemoveParams(filterLabel: FilterLabel): Observable<Params> {
|
getRemoveParams(filterField: string, filterValue: string): Observable<Params> {
|
||||||
return this.appliedFilters.pipe(
|
return this.appliedFilters.pipe(
|
||||||
map((filters) => {
|
map((filters) => {
|
||||||
const values = [];
|
const field: string = Object.keys(filters).find((f) => f === filterField);
|
||||||
filters.forEach((filter) => {
|
const newValues = hasValue(filters[field]) ? filters[field].filter((v) => v !== filterValue) : null;
|
||||||
if (filter.field === filterLabel.field && filter.value !== filterLabel.value) {
|
|
||||||
values.push(filter.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
[filterLabel.field]: values,
|
[field]: isNotEmpty(newValues) ? newValues : null,
|
||||||
page: 1
|
page: 1
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
getSearchLink() {
|
getSearchLink() {
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
export class FilterLabel {
|
|
||||||
value: string;
|
|
||||||
field: string;
|
|
||||||
constructor(value: string, field: string) {
|
|
||||||
this.value = value;
|
|
||||||
this.field = field;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -40,8 +40,6 @@ import { ListableObject } from '../../shared/object-collection/shared/listable-o
|
|||||||
import { FacetValueResponseParsingService } from '../../core/data/facet-value-response-parsing.service';
|
import { FacetValueResponseParsingService } from '../../core/data/facet-value-response-parsing.service';
|
||||||
import { FacetConfigResponseParsingService } from '../../core/data/facet-config-response-parsing.service';
|
import { FacetConfigResponseParsingService } from '../../core/data/facet-config-response-parsing.service';
|
||||||
import { PaginatedSearchOptions } from '../paginated-search-options.model';
|
import { PaginatedSearchOptions } from '../paginated-search-options.model';
|
||||||
import { FilterLabel } from './filter-label.model';
|
|
||||||
import { combineLatest } from 'rxjs/observable/combineLatest';
|
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { CollectionDataService } from '../../core/data/collection-data.service';
|
import { CollectionDataService } from '../../core/data/collection-data.service';
|
||||||
|
@@ -49,22 +49,23 @@ export class SearchSettingsComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.searchOptions = this.service.searchOptions;
|
|
||||||
this.pageSize = this.searchOptions.pagination.pageSize;
|
|
||||||
this.pageSizeOptions = this.searchOptions.pagination.pageSizeOptions;
|
|
||||||
this.filterService.getPaginatedSearchOptions(this.defaults).first().subscribe((options) => {
|
this.filterService.getPaginatedSearchOptions(this.defaults).first().subscribe((options) => {
|
||||||
this.direction = options.sort.direction;
|
this.direction = options.sort.direction;
|
||||||
this.field = options.sort.field;
|
this.field = options.sort.field;
|
||||||
this.pageSize = options.pagination.pageSize;
|
this.pageSize = options.pagination.pageSize;
|
||||||
|
this.searchOptions = options;
|
||||||
|
this.pageSize = options.pagination.pageSize;
|
||||||
|
this.pageSizeOptions = options.pagination.pageSizeOptions
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadRPP(event: Event) {
|
reloadRPP(event: Event) {
|
||||||
const value = (event.target as HTMLInputElement).value;
|
const value = (event.target as HTMLInputElement).value;
|
||||||
const navigationExtras: NavigationExtras = {
|
const navigationExtras: NavigationExtras = {
|
||||||
queryParams: Object.assign({}, this.currentParams, {
|
queryParams: {
|
||||||
pageSize: value
|
pageSize: value,
|
||||||
})
|
},
|
||||||
|
queryParamsHandling: 'merge'
|
||||||
};
|
};
|
||||||
this.router.navigate([ '/search' ], navigationExtras);
|
this.router.navigate([ '/search' ], navigationExtras);
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,7 @@ import { EmphasizePipe } from './utils/emphasize.pipe';
|
|||||||
import { InputSuggestionsComponent } from './input-suggestions/input-suggestions.component';
|
import { InputSuggestionsComponent } from './input-suggestions/input-suggestions.component';
|
||||||
import { CapitalizePipe } from './utils/capitalize.pipe';
|
import { CapitalizePipe } from './utils/capitalize.pipe';
|
||||||
import { MomentModule } from 'angular2-moment';
|
import { MomentModule } from 'angular2-moment';
|
||||||
|
import { ObjectKeysPipe } from './utils/object-keys-pipe';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -76,7 +77,8 @@ const PIPES = [
|
|||||||
SafeUrlPipe,
|
SafeUrlPipe,
|
||||||
TruncatePipe,
|
TruncatePipe,
|
||||||
EmphasizePipe,
|
EmphasizePipe,
|
||||||
CapitalizePipe
|
CapitalizePipe,
|
||||||
|
ObjectKeysPipe
|
||||||
];
|
];
|
||||||
|
|
||||||
const COMPONENTS = [
|
const COMPONENTS = [
|
||||||
|
10
src/app/shared/utils/object-keys-pipe.ts
Normal file
10
src/app/shared/utils/object-keys-pipe.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { PipeTransform, Pipe } from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({name: 'dsObjectKeys'})
|
||||||
|
export class ObjectKeysPipe implements PipeTransform {
|
||||||
|
transform(value, args:string[]): any {
|
||||||
|
const keys = [];
|
||||||
|
Object.keys(value).forEach((k) => keys.push(k));
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user