latest fixes for search page

This commit is contained in:
lotte
2018-07-19 13:44:38 +02:00
parent 6deac6b021
commit cfc448332d
11 changed files with 72 additions and 62 deletions

View File

@@ -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();

View File

@@ -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;

View File

@@ -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> {

View File

@@ -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'
}); });

View File

@@ -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)">
<a *ngFor="let values of (appliedFilters | async)[key]" class="badge badge-primary mr-1"
[routerLink]="getSearchLink()" [routerLink]="getSearchLink()"
[queryParams]="(getRemoveParams(label) | async)" queryParamsHandling="merge"> [queryParams]="(getRemoveParams(key, values) | async)" queryParamsHandling="merge">
{{label.value}} {{values}}
<span> ×</span> <span> ×</span>
</a> </a>
</ng-container>
</div> </div>
</div> </div>

View File

@@ -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() {

View File

@@ -1,8 +0,0 @@
export class FilterLabel {
value: string;
field: string;
constructor(value: string, field: string) {
this.value = value;
this.field = field;
}
}

View File

@@ -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';

View File

@@ -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);
} }

View File

@@ -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 = [

View 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;
}
}