clean up of selected values

This commit is contained in:
lotte
2018-07-20 14:32:07 +02:00
parent dedf62dfa6
commit 6e28bcd0bc
9 changed files with 102 additions and 107 deletions

View File

@@ -1,16 +1,16 @@
<div> <div>
<div class="filters py-2"> <div class="filters py-2">
<a *ngFor="let value of selectedValues" class="d-flex flex-row" <a *ngFor="let value of (selectedValues | async)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getRemoveParams(value)" queryParamsHandling="merge"> [queryParams]="getRemoveParams(value) | async" queryParamsHandling="merge">
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
<span class="filter-value pl-1">{{value}}</span> <span class="filter-value pl-1">{{value}}</span>
</a> </a>
<ng-container *ngFor="let page of (filterValues$ | async)"> <ng-container *ngFor="let page of (filterValues$ | async)">
<ng-container *ngFor="let value of (page | async)?.payload.page; let i=index"> <ng-container *ngFor="let value of (page | async)?.payload.page; let i=index">
<a *ngIf="!selectedValues.includes(value.value)" class="d-flex flex-row" <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getAddParams(value.value)" queryParamsHandling="merge"> [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge">
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
<span class="filter-value px-1">{{value.value}}</span> <span class="filter-value px-1">{{value.value}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">

View File

@@ -2,7 +2,7 @@ import { Component, Injector, Input, OnInit } from '@angular/core';
import { renderFilterType } from '../search-filter-type-decorator'; import { renderFilterType } from '../search-filter-type-decorator';
import { FilterType } from '../../../search-service/filter-type.model'; import { FilterType } from '../../../search-service/filter-type.model';
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
import { FILTER_CONFIG, SELECTED_VALUES } from '../search-filter.service'; import { FILTER_CONFIG } from '../search-filter.service';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
@Component({ @Component({
@@ -18,14 +18,11 @@ export class SearchFacetFilterWrapperComponent implements OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.selectedValues.subscribe((values) => { this.objectInjector = Injector.create({
this.objectInjector = Injector.create({ providers: [
providers: [ { provide: FILTER_CONFIG, useFactory: () => (this.filterConfig), deps: [] }
{ provide: FILTER_CONFIG, useFactory: () => (this.filterConfig), deps: [] }, ],
{ provide: SELECTED_VALUES, useFactory: () => (values), deps: [] }], parent: this.injector
parent: this.injector
});
}); });
} }

View File

@@ -1,17 +1,9 @@
import { import { Component, Inject, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
Component,
ElementRef,
Inject,
OnDestroy,
OnInit, QueryList,
ViewChild,
ViewChildren
} from '@angular/core';
import { FacetValue } from '../../../search-service/facet-value.model'; import { FacetValue } from '../../../search-service/facet-value.model';
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { FILTER_CONFIG, SearchFilterService, SELECTED_VALUES } from '../search-filter.service'; import { FILTER_CONFIG, SearchFilterService } from '../search-filter.service';
import { hasNoValue, hasValue, isNotEmpty } from '../../../../shared/empty.util'; import { hasNoValue, hasValue, isNotEmpty } from '../../../../shared/empty.util';
import { RemoteData } from '../../../../core/data/remote-data'; import { RemoteData } from '../../../../core/data/remote-data';
import { PaginatedList } from '../../../../core/data/paginated-list'; import { PaginatedList } from '../../../../core/data/paginated-list';
@@ -20,6 +12,7 @@ import { SearchOptions } from '../../../search-options.model';
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/Subscription'; import { Subscription } from 'rxjs/Subscription';
import { EmphasizePipe } from '../../../../shared/utils/emphasize.pipe'; import { EmphasizePipe } from '../../../../shared/utils/emphasize.pipe';
import { tap } from 'rxjs/operators';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -32,7 +25,7 @@ import { EmphasizePipe } from '../../../../shared/utils/emphasize.pipe';
template: ``, template: ``,
}) })
export class SearchFacetFilterComponent implements OnInit, OnDestroy { export class SearchFacetFilterComponent implements OnInit, OnDestroy, OnChanges {
filterValues: Array<Observable<RemoteData<PaginatedList<FacetValue>>>> = []; filterValues: Array<Observable<RemoteData<PaginatedList<FacetValue>>>> = [];
filterValues$: BehaviorSubject<any> = new BehaviorSubject(this.filterValues); filterValues$: BehaviorSubject<any> = new BehaviorSubject(this.filterValues);
currentPage: Observable<number>; currentPage: Observable<number>;
@@ -41,27 +34,33 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
pageChange = false; pageChange = false;
sub: Subscription; sub: Subscription;
filterSearchResults: Observable<any[]> = Observable.of([]); filterSearchResults: Observable<any[]> = Observable.of([]);
selectedValues: Observable<string[]>;
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
protected filterService: SearchFilterService, protected filterService: SearchFilterService,
protected router: Router, protected router: Router,
@Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig) {
@Inject(SELECTED_VALUES) public selectedValues: string[]) {
} }
ngOnInit(): void { ngOnInit(): void {
this.currentPage = this.getCurrentPage(); this.currentPage = this.getCurrentPage();
this.selectedValues = this.filterService.getSelectedValuesForFilter(this.filterConfig);
this.filterService.getSearchOptions().distinctUntilChanged().subscribe((options) => this.updateFilterValueList(options)); this.filterService.getSearchOptions().distinctUntilChanged().subscribe((options) => this.updateFilterValueList(options));
} }
updateFilterValueList(options: SearchOptions) { updateFilterValueList(options: SearchOptions) {
this.unsubscribe(); this.unsubscribe();
this.showFirstPageOnly(); this.showFirstPageOnly();
let page;
this.sub = this.currentPage.distinctUntilChanged().map((page) => { this.sub = this.currentPage.distinctUntilChanged().map((p) => {
return this.searchService.getFacetValuesFor(this.filterConfig, page, options); page = p;
return this.searchService.getFacetValuesFor(this.filterConfig, p, options).pipe(tap((rd) => {if (this.filterConfig.paramName === 'f.author') console.log(rd.isLoading, rd.hasSucceeded, rd.payload)}));
}).subscribe((newValues$) => { }).subscribe((newValues$) => {
this.filterValues = [...this.filterValues, newValues$]; if (page > 1) {
this.filterValues = [...this.filterValues, newValues$];
} else {
this.filterValues = [newValues$]
}
this.filterValues$.next(this.filterValues); this.filterValues$.next(this.filterValues);
newValues$.first().subscribe((rd) => this.isLastPage$.next(hasNoValue(rd.payload.next))); newValues$.first().subscribe((rd) => this.isLastPage$.next(hasNoValue(rd.payload.next)));
}); });
@@ -81,7 +80,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
} }
showFirstPageOnly() { showFirstPageOnly() {
this.filterValues = []; // this.filterValues = [];
this.filterService.resetPage(this.filterConfig.name); this.filterService.resetPage(this.filterConfig.name);
} }
@@ -94,15 +93,18 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
} }
onSubmit(data: any) { onSubmit(data: any) {
if (isNotEmpty(data)) { this.selectedValues.first().subscribe((selectedValues) => {
this.router.navigate([this.getSearchLink()], { if (isNotEmpty(data)) {
queryParams: this.router.navigate([this.getSearchLink()], {
{ [this.filterConfig.paramName]: [...this.selectedValues, data] }, queryParams:
queryParamsHandling: 'merge' { [this.filterConfig.paramName]: [...selectedValues, data] },
}); queryParamsHandling: 'merge'
this.filter = ''; });
} this.filter = '';
this.filterSearchResults = Observable.of([]); }
this.filterSearchResults = Observable.of([]);
}
)
} }
onClick(data: any) { onClick(data: any) {
@@ -113,18 +115,22 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
return hasValue(o); return hasValue(o);
} }
getRemoveParams(value: string) { getRemoveParams(value: string): Observable<any> {
return { return this.selectedValues.map((selectedValues) => {
[this.filterConfig.paramName]: this.selectedValues.filter((v) => v !== value), return {
page: 1 [this.filterConfig.paramName]: selectedValues.filter((v) => v !== value),
}; page: 1
};
});
} }
getAddParams(value: string) { getAddParams(value: string): Observable<any> {
return { return this.selectedValues.map((selectedValues) => {
[this.filterConfig.paramName]: [...this.selectedValues, value], return {
page: 1 [this.filterConfig.paramName]: [...selectedValues, value],
}; page: 1
};
});
} }
ngOnDestroy(): void { ngOnDestroy(): void {
@@ -161,4 +167,8 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
return new EmphasizePipe().transform(facet.value, query) + ' (' + facet.count + ')'; return new EmphasizePipe().transform(facet.value, query) + ' (' + facet.count + ')';
} }
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
} }

View File

@@ -2,6 +2,6 @@
<div (click)="toggle()" class="filter-name"><h5 class="d-inline-block mb-0">{{'search.filters.filter.' + filter.name + '.head'| translate}}</h5> <span class="filter-toggle fa float-right" <div (click)="toggle()" class="filter-name"><h5 class="d-inline-block mb-0">{{'search.filters.filter.' + filter.name + '.head'| translate}}</h5> <span class="filter-toggle fa float-right"
[ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div> [ngClass]="(isCollapsed() | async) ? 'fa-plus' : 'fa-minus'"></span></div>
<div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : collapsed}"> <div [@slide]="(isCollapsed() | async) ? 'collapsed' : 'expanded'" (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : collapsed}">
<ds-search-facet-filter-wrapper [filterConfig]="filter" [selectedValues]="getSelectedValues()"></ds-search-facet-filter-wrapper> <ds-search-facet-filter-wrapper [filterConfig]="filter"></ds-search-facet-filter-wrapper>
</div> </div>
</div> </div>

View File

@@ -1,21 +1,21 @@
import { Injectable, InjectionToken } from '@angular/core'; import { Injectable, InjectionToken } from '@angular/core';
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; import { distinctUntilChanged, map } from 'rxjs/operators';
import { SearchFiltersState, SearchFilterState } from './search-filter.reducer'; import { SearchFiltersState, SearchFilterState } from './search-filter.reducer';
import { createSelector, MemoizedSelector, Store } from '@ngrx/store'; import { createSelector, MemoizedSelector, Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable'; import { Observable } from 'rxjs/Observable';
import { import {
SearchFilterCollapseAction, SearchFilterCollapseAction,
SearchFilterDecrementPageAction, SearchFilterExpandAction, SearchFilterDecrementPageAction,
SearchFilterExpandAction,
SearchFilterIncrementPageAction, SearchFilterIncrementPageAction,
SearchFilterInitialCollapseAction, SearchFilterInitialCollapseAction,
SearchFilterInitialExpandAction, SearchFilterResetPageAction, SearchFilterInitialExpandAction,
SearchFilterResetPageAction,
SearchFilterToggleAction SearchFilterToggleAction
} from './search-filter.actions'; } from './search-filter.actions';
import { hasValue, isEmpty, isNotEmpty, } from '../../../shared/empty.util'; import { hasValue, isEmpty, isNotEmpty, } from '../../../shared/empty.util';
import { SearchFilterConfig } from '../../search-service/search-filter-config.model'; import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
import { SearchService } from '../../search-service/search.service';
import { RouteService } from '../../../shared/services/route.service'; import { RouteService } from '../../../shared/services/route.service';
import ObjectExpression from 'rollup/dist/typings/ast/nodes/ObjectExpression';
import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model'; import { SortDirection, SortOptions } from '../../../core/cache/models/sort-options.model';
import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model'; import { PaginationComponentOptions } from '../../../shared/pagination/pagination-component-options.model';
import { SearchOptions } from '../../search-options.model'; import { SearchOptions } from '../../search-options.model';
@@ -25,7 +25,6 @@ import { ActivatedRoute, Params } from '@angular/router';
const filterStateSelector = (state: SearchFiltersState) => state.searchFilter; const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
export const FILTER_CONFIG: InjectionToken<SearchFilterConfig> = new InjectionToken<SearchFilterConfig>('filterConfig'); export const FILTER_CONFIG: InjectionToken<SearchFilterConfig> = new InjectionToken<SearchFilterConfig>('filterConfig');
export const SELECTED_VALUES: InjectionToken<string[]> = new InjectionToken<string[]>('selectedValues');
@Injectable() @Injectable()
export class SearchFilterService { export class SearchFilterService {

View File

@@ -1,16 +1,16 @@
<div> <div>
<div class="filters py-2"> <div class="filters py-2">
<a *ngFor="let value of selectedValues" class="d-flex flex-row" <a *ngFor="let value of (selectedValues | async)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getRemoveParams(value)" queryParamsHandling="merge"> [queryParams]="getRemoveParams(value) | async" queryParamsHandling="merge">
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
<span class="filter-value pl-1">{{value}}</span> <span class="filter-value pl-1">{{value}}</span>
</a> </a>
<ng-container *ngFor="let page of (filterValues$ | async)"> <ng-container *ngFor="let page of (filterValues$ | async)">
<ng-container *ngFor="let value of (page | async)?.payload.page; let i=index"> <ng-container *ngFor="let value of (page | async)?.payload.page; let i=index">
<a *ngIf="!selectedValues.includes(value.value)" class="d-flex flex-row" <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getAddParams(value.value)" queryParamsHandling="merge" > [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge" >
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
<span class="filter-value px-1">{{value.value}}</span> <span class="filter-value px-1">{{value.value}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">

View File

@@ -25,9 +25,9 @@
</ng-container> </ng-container>
<ng-container *ngFor="let page of (filterValues$ | async)"> <ng-container *ngFor="let page of (filterValues$ | async)">
<ng-container *ngFor="let value of (page | async)?.payload.page; let i=index"> <ng-container *ngFor="let value of (page | async)?.payload.page; let i=index">
<a *ngIf="!selectedValues.includes(value.value)" class="d-flex flex-row" <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getAddParams(value.value)" queryParamsHandling="merge"> [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge">
<span class="filter-value px-1">{{value.value}}</span> <span class="filter-value px-1">{{value.value}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">
<span class="badge badge-secondary badge-pill">{{value.count}}</span> <span class="badge badge-secondary badge-pill">{{value.count}}</span>

View File

@@ -1,14 +1,14 @@
import { isPlatformBrowser } from '@angular/common'; import { isPlatformBrowser } from '@angular/common';
import { Component, Inject, OnChanges, OnInit, PLATFORM_ID } from '@angular/core'; import { Component, Inject, 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';
import { isNotEmpty } from '../../../../shared/empty.util';
import { SearchFilterConfig } from '../../../search-service/search-filter-config.model'; import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
import { FILTER_CONFIG, SearchFilterService, SELECTED_VALUES } from '../search-filter.service'; import { FILTER_CONFIG, SearchFilterService } from '../search-filter.service';
import { SearchService } from '../../../search-service/search.service'; import { SearchService } from '../../../search-service/search.service';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import * as moment from 'moment'; import * as moment from 'moment';
import { Observable } from 'rxjs/Observable';
/** /**
* This component renders a simple item page. * This component renders a simple item page.
@@ -31,14 +31,14 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
min = 1950; min = 1950;
max = 2018; max = 2018;
range; range;
constructor(protected searchService: SearchService, constructor(protected searchService: SearchService,
protected filterService: SearchFilterService, protected filterService: SearchFilterService,
protected router: Router, protected router: Router,
@Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig, @Inject(FILTER_CONFIG) public filterConfig: SearchFilterConfig,
@Inject(SELECTED_VALUES) public selectedValues: string[],
@Inject(PLATFORM_ID) private platformId: any, @Inject(PLATFORM_ID) private platformId: any,
private route: ActivatedRoute) { private route: ActivatedRoute) {
super(searchService, filterService, router, filterConfig, selectedValues); super(searchService, filterService, router, filterConfig);
} }
ngOnInit(): void { ngOnInit(): void {
@@ -51,52 +51,41 @@ 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;
const max = parts.length > 1 ? parts[1].trim() : value; const max = parts.length > 1 ? parts[1].trim() : value;
return { return Observable.of(
[this.filterConfig.paramName + minSuffix]: [min], {
[this.filterConfig.paramName + maxSuffix]: [max], [this.filterConfig.paramName + minSuffix]: [min],
page: 1 [this.filterConfig.paramName + maxSuffix]: [max],
}; page: 1
});
} }
getRemoveParams(value: string) { getRemoveParams(value: string) {
return { return Observable.of(
[this.filterConfig.paramName + minSuffix]: null, {
[this.filterConfig.paramName + maxSuffix]: null, [this.filterConfig.paramName + minSuffix]: null,
page: 1 [this.filterConfig.paramName + maxSuffix]: null,
}; page: 1
}
);
} }
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 newMin = this.range[0] !== this.min ? [this.range[0]] : null;
const newMax = this.range[1] !== this.max ? [this.range[1]] : 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]: newMin, [this.filterConfig.paramName + minSuffix]: newMin,
[this.filterConfig.paramName + maxSuffix]: newMax [this.filterConfig.paramName + maxSuffix]: newMax
}, },
queryParamsHandling: 'merge' queryParamsHandling: 'merge'
}); });
this.filter = ''; this.filter = '';
} }
/** /**

View File

@@ -1,16 +1,16 @@
<div> <div>
<div class="filters py-2"> <div class="filters py-2">
<a *ngFor="let value of selectedValues" class="d-flex flex-row" <a *ngFor="let value of (selectedValues | async)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getRemoveParams(value)" queryParamsHandling="merge"> [queryParams]="getRemoveParams(value) | async" queryParamsHandling="merge">
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
<span class="filter-value pl-1">{{value}}</span> <span class="filter-value pl-1">{{value}}</span>
</a> </a>
<ng-container *ngFor="let page of (filterValues$ | async)"> <ng-container *ngFor="let page of (filterValues$ | async)">
<ng-container *ngFor="let value of (page | async)?.payload.page; let i=index"> <ng-container *ngFor="let value of (page | async)?.payload.page; let i=index">
<a *ngIf="!selectedValues.includes(value.value)" class="d-flex flex-row" <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
[routerLink]="[getSearchLink()]" [routerLink]="[getSearchLink()]"
[queryParams]="getAddParams(value.value)" queryParamsHandling="merge" > [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge" >
<input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/> <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
<span class="filter-value px-1">{{value.value}}</span> <span class="filter-value px-1">{{value.value}}</span>
<span class="float-right filter-value-count ml-auto"> <span class="float-right filter-value-count ml-auto">