From fc73fc1d3ea8b497390aafe7a7e55a61e5c6eef0 Mon Sep 17 00:00:00 2001
From: lotte <lotte_hofstede@hotmail.com>
Date: Wed, 20 Mar 2019 16:57:55 +0100
Subject: [PATCH] optimizations links in facets

---
 package.json                                  |  1 +
 .../search-boolean-filter.component.html      | 20 +----
 .../search-facet-option.component.html        |  9 ++
 .../search-facet-option.component.ts          | 78 ++++++++++++++++
 .../search-facet-range-option.component.html  |  8 ++
 .../search-facet-range-option.component.ts    | 88 +++++++++++++++++++
 ...earch-facet-selected-option.component.html |  6 ++
 .../search-facet-selected-option.component.ts | 67 ++++++++++++++
 ...search-facet-filter-wrapper.component.html |  2 +-
 .../search-facet-filter-wrapper.component.ts  |  6 +-
 .../search-facet-filter.component.ts          |  4 +
 .../search-filter/search-filter.actions.ts    | 20 ++---
 .../search-filter.component.html              |  6 +-
 .../search-filter/search-filter.component.ts  | 75 ++++++++++------
 .../search-filter/search-filter.reducer.ts    | 37 +++-----
 .../search-filter.service.spec.ts             | 20 ++---
 .../search-filter/search-filter.service.ts    | 40 ++++-----
 .../search-hierarchy-filter.component.html    | 13 +--
 .../search-range-filter.component.html        |  9 +-
 .../search-range-filter.component.ts          | 30 ++-----
 .../search-text-filter.component.html         | 14 +--
 .../search-filters.component.html             |  2 +-
 .../search-filters.component.ts               | 32 +------
 src/app/+search-page/search-page.component.ts |  1 -
 src/app/+search-page/search-page.module.ts    |  9 ++
 src/app/shared/services/route.service.ts      |  9 +-
 src/main.browser.ts                           |  1 +
 yarn.lock                                     | 43 +++++++++
 28 files changed, 445 insertions(+), 205 deletions(-)
 create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
 create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts
 create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html
 create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts
 create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html
 create mode 100644 src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts

diff --git a/package.json b/package.json
index fd037de3f7..7f319d9716 100644
--- a/package.json
+++ b/package.json
@@ -119,6 +119,7 @@
     "pem": "1.12.3",
     "reflect-metadata": "0.1.12",
     "rxjs": "6.2.2",
+    "rxjs-spy": "^7.5.1",
     "sortablejs": "1.7.0",
     "text-mask-core": "5.0.1",
     "ts-loader": "^5.2.1",
diff --git a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html
index 216683c122..06154916b2 100644
--- a/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-boolean-filter/search-boolean-filter.component.html
@@ -1,24 +1,10 @@
 <div>
     <div class="filters py-2">
-        <a *ngFor="let value of (selectedValues | async)" class="d-flex flex-row"
-           [routerLink]="[getSearchLink()]"
-           [queryParams]="getRemoveParams(value) | async" queryParamsHandling="merge">
-            <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
-            <span class="filter-value pl-1">{{value}}</span>
-        </a>
+        <ds-search-facet-selected-option *ngFor="let value of (selectedValues | async)" [selectedValue]="value" [filterConfig]="filterConfig"></ds-search-facet-selected-option>
       <ng-container *ngFor="let page of (filterValues$ | async)?.payload">
         <div [@facetLoad]="animationState">
-          <ng-container *ngFor="let value of page.page; trackBy: trackUpdate">
-                <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
-                   [routerLink]="[getSearchLink()]"
-                   [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge">
-                    <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
-                    <span class="filter-value px-1">{{value.value}}</span>
-                    <span class="float-right filter-value-count ml-auto">
-                        <span class="badge badge-secondary badge-pill">{{value.count}}</span>
-                    </span>
-                </a>
-            </ng-container>
+            <ds-search-facet-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value">
+            </ds-search-facet-option>
         </div>
         </ng-container>
         <div class="clearfix toggle-more-filters">
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
new file mode 100644
index 0000000000..881fb98dcb
--- /dev/null
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.html
@@ -0,0 +1,9 @@
+<a *ngIf="isVisible" class="d-flex flex-row"
+   [routerLink]="[getSearchLink()]"
+   [queryParams]="addQueryParams | async" queryParamsHandling="merge">
+    <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
+    <span class="filter-value px-1">{{filterValue.value}}</span>
+    <span class="float-right filter-value-count ml-auto">
+                        <span class="badge badge-secondary badge-pill">{{filterValue.count}}</span>
+                    </span>
+</a>
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts
new file mode 100644
index 0000000000..c5896f92b6
--- /dev/null
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component.ts
@@ -0,0 +1,78 @@
+import { Observable, of as observableOf } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { Component, Input, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FacetValue } from '../../../../search-service/facet-value.model';
+import { SearchFilterConfig } from '../../../../search-service/search-filter-config.model';
+import { SearchService } from '../../../../search-service/search.service';
+import { SearchFilterService } from '../../search-filter.service';
+
+@Component({
+  selector: 'ds-search-facet-option',
+  templateUrl: './search-facet-option.component.html',
+})
+
+/**
+ * Represents a single option in a filter facet
+ */
+export class SearchFacetOptionComponent implements OnInit {
+  /**
+   * A single value for this component
+   */
+  @Input() filterValue: FacetValue;
+  @Input() filterConfig: SearchFilterConfig;
+
+  /**
+   * Emits the active values for this filter
+   */
+  selectedValues$: Observable<string[]>;
+
+  isVisible: Observable<boolean>;
+
+  addQueryParams;
+
+  constructor(protected searchService: SearchService,
+              protected filterService: SearchFilterService,
+              protected router: Router
+  ) {
+  }
+
+  /**
+   * Initializes all observable instance variables and starts listening to them
+   */
+  ngOnInit(): void {
+    this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig);
+    this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
+    this.addQueryParams = this.getAddParams();
+  }
+
+  /**
+   * Checks if a value for this filter is currently active
+   */
+  private isChecked(): Observable<boolean> {
+    return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.filterValue.value);
+  }
+
+  /**
+   * @returns {string} The base path to the search page
+   */
+  getSearchLink() {
+    return this.searchService.getSearchLink();
+  }
+
+  /**
+   * Calculates the parameters that should change if a given value for this filter would be added to the active filters
+   * @param {string} value The value that is added for this filter
+   * @returns {Observable<any>} The changed filter parameters
+   */
+  private getAddParams(): Observable<any> {
+    return this.selectedValues$.pipe(map((selectedValues) => {
+      return {
+        [this.filterConfig.paramName]: [...selectedValues, this.filterValue.value],
+        page: 1
+      };
+    }));
+  }
+
+}
+
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html
new file mode 100644
index 0000000000..92e90a00cc
--- /dev/null
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.html
@@ -0,0 +1,8 @@
+<a *ngIf="isVisible" class="d-flex flex-row"
+   [routerLink]="[getSearchLink()]"
+   [queryParams]="changeQueryParams | async" queryParamsHandling="merge">
+    <span class="filter-value px-1">{{filterValue.value}}</span>
+    <span class="float-right filter-value-count ml-auto">
+                        <span class="badge badge-secondary badge-pill">{{filterValue.count}}</span>
+                    </span>
+</a>
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts
new file mode 100644
index 0000000000..0b38ca1845
--- /dev/null
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component.ts
@@ -0,0 +1,88 @@
+import { Observable, of as observableOf } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { Component, Input, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FacetValue } from '../../../../search-service/facet-value.model';
+import { SearchFilterConfig } from '../../../../search-service/search-filter-config.model';
+import { SearchService } from '../../../../search-service/search.service';
+import { SearchFilterService } from '../../search-filter.service';
+import {
+  RANGE_FILTER_MAX_SUFFIX,
+  RANGE_FILTER_MIN_SUFFIX
+} from '../../search-range-filter/search-range-filter.component';
+
+const rangeDelimiter = '-';
+
+@Component({
+  selector: 'ds-search-facet-range-option',
+  templateUrl: './search-facet-range-option.component.html',
+})
+
+/**
+ * Represents a single option in a filter facet
+ */
+export class SearchFacetRangeOptionComponent implements OnInit {
+  /**
+   * A single value for this component
+   */
+  @Input() filterValue: FacetValue;
+  @Input() filterConfig: SearchFilterConfig;
+
+  /**
+   * Emits the active values for this filter
+   */
+  selectedValues$: Observable<string[]>;
+
+  isVisible: Observable<boolean>;
+
+  changeQueryParams;
+
+  constructor(protected searchService: SearchService,
+              protected filterService: SearchFilterService,
+              protected router: Router
+  ) {
+  }
+
+  /**
+   * Initializes all observable instance variables and starts listening to them
+   */
+  ngOnInit(): void {
+    this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig);
+    this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
+    this.changeQueryParams = this.getChangeParams();
+  }
+
+  /**
+   * Checks if a value for this filter is currently active
+   */
+  private isChecked(): Observable<boolean> {
+    return this.filterService.isFilterActiveWithValue(this.filterConfig.paramName, this.filterValue.value);
+  }
+
+  /**
+   * @returns {string} The base path to the search page
+   */
+  getSearchLink() {
+    return this.searchService.getSearchLink();
+  }
+
+
+  /**
+   * Calculates the parameters that should change if a given values for this range filter would be changed
+   * @param {string} value The values that are changed for this filter
+   * @returns {Observable<any>} The changed filter parameters
+   */
+  getChangeParams() {
+    const parts = this.filterValue.value.split(rangeDelimiter);
+    const min = parts.length > 1 ? parts[0].trim() : this.filterValue.value;
+    const max = parts.length > 1 ? parts[1].trim() : this.filterValue.value;
+    return observableOf(
+      {
+        [this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX]: [min],
+        [this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX]: [max],
+        page: 1
+      });
+  }
+
+}
+
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html
new file mode 100644
index 0000000000..7bed620770
--- /dev/null
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.html
@@ -0,0 +1,6 @@
+<a class="d-flex flex-row"
+   [routerLink]="[getSearchLink()]"
+   [queryParams]="removeQueryParams | async" queryParamsHandling="merge">
+    <input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
+    <span class="filter-value pl-1">{{selectedValue}}</span>
+</a>
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts
new file mode 100644
index 0000000000..2fdc490d68
--- /dev/null
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component.ts
@@ -0,0 +1,67 @@
+import { Observable, of as observableOf } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { Component, Input, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FacetValue } from '../../../../search-service/facet-value.model';
+import { SearchFilterConfig } from '../../../../search-service/search-filter-config.model';
+import { SearchService } from '../../../../search-service/search.service';
+import { SearchFilterService } from '../../search-filter.service';
+
+@Component({
+  selector: 'ds-search-facet-selected-option',
+  templateUrl: './search-facet-selected-option.component.html',
+})
+
+/**
+ * Represents a single option in a filter facet
+ */
+export class SearchFacetSelectedOptionComponent implements OnInit {
+  /**
+   * A single value for this component
+   */
+  @Input() selectedValue: string;
+  @Input() filterConfig: SearchFilterConfig;
+
+  /**
+   * Emits the active values for this filter
+   */
+  selectedValues$: Observable<string[]>;
+
+  removeQueryParams;
+
+  constructor(protected searchService: SearchService,
+              protected filterService: SearchFilterService,
+              protected router: Router
+  ) {
+  }
+
+  /**
+   * Initializes all observable instance variables and starts listening to them
+   */
+  ngOnInit(): void {
+    this.selectedValues$ = this.filterService.getSelectedValuesForFilter(this.filterConfig);
+    this.removeQueryParams = this.getRemoveParams();
+  }
+
+  /**
+   * @returns {string} The base path to the search page
+   */
+  getSearchLink() {
+    return this.searchService.getSearchLink();
+  }
+
+  /**
+   * Calculates the parameters that should change if a given value for this filter would be removed from the active filters
+   * @param {string} value The value that is removed for this filter
+   * @returns {Observable<any>} The changed filter parameters
+   */
+  private getRemoveParams(): Observable<any> {
+    return this.selectedValues$.pipe(map((selectedValues) => {
+      return {
+        [this.filterConfig.paramName]: selectedValues.filter((v) => v !== this.selectedValue),
+        page: 1
+      };
+    }));
+  }
+}
+
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html
index b7e03af473..4a325d9b3c 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.html
@@ -1 +1 @@
-<ng-container *ngComponentOutlet="getSearchFilter(); injector: objectInjector;"></ng-container>
+<ng-container *ngComponentOutlet="searchFilter injector: objectInjector;"></ng-container>
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts
index bc088777fa..5b733b52cb 100644
--- a/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-facet-filter-wrapper/search-facet-filter-wrapper.component.ts
@@ -3,6 +3,8 @@ import { renderFilterType } from '../search-filter-type-decorator';
 import { FilterType } from '../../../search-service/filter-type.model';
 import { SearchFilterConfig } from '../../../search-service/search-filter-config.model';
 import { FILTER_CONFIG } from '../search-filter.service';
+import { GenericConstructor } from '../../../../core/shared/generic-constructor';
+import { SearchFacetFilterComponent } from '../search-facet-filter/search-facet-filter.component';
 
 @Component({
   selector: 'ds-search-facet-filter-wrapper',
@@ -18,6 +20,7 @@ export class SearchFacetFilterWrapperComponent implements OnInit {
    */
   @Input() filterConfig: SearchFilterConfig;
 
+  searchFilter: GenericConstructor<SearchFacetFilterComponent>;
   /**
    * Injector to inject a child component with the @Input parameters
    */
@@ -30,6 +33,7 @@ export class SearchFacetFilterWrapperComponent implements OnInit {
    * Initialize and add the filter config to the injector
    */
   ngOnInit(): void {
+    this.searchFilter = this.getSearchFilter();
     this.objectInjector = Injector.create({
       providers: [
         { provide: FILTER_CONFIG, useFactory: () => (this.filterConfig), deps: [] }
@@ -41,7 +45,7 @@ export class SearchFacetFilterWrapperComponent implements OnInit {
   /**
    * Find the correct component based on the filter config's type
    */
-  getSearchFilter() {
+  private getSearchFilter() {
     const type: FilterType = this.filterConfig.type;
     return renderFilterType(type);
   }
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 f4f835c152..74c2794313 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
@@ -85,8 +85,11 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
    * Initializes all observable instance variables and starts listening to them
    */
   ngOnInit(): void {
+    console.log('renderSearchFacetFilterComponent')
+
     this.filterValues$ = new BehaviorSubject(new RemoteData(true, false, undefined, undefined, undefined));
     this.currentPage = this.getCurrentPage().pipe(distinctUntilChanged());
+
     this.selectedValues = this.filterService.getSelectedValuesForFilter(this.filterConfig);
     const searchOptions = this.searchConfigService.searchOptions;
     this.subs.push(this.searchConfigService.searchOptions.subscribe(() => this.updateFilterValueList()));
@@ -190,6 +193,7 @@ export class SearchFacetFilterComponent implements OnInit, OnDestroy {
    * @param data The string from the input field
    */
   onSubmit(data: any) {
+    console.log('onsubmit');
     this.selectedValues.pipe(take(1)).subscribe((selectedValues) => {
         if (isNotEmpty(data)) {
           this.router.navigate([this.getSearchLink()], {
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts b/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts
index 2e556b32d6..838597e03d 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.actions.ts
@@ -1,6 +1,7 @@
 import { Action } from '@ngrx/store';
 
 import { type } from '../../../shared/ngrx/type';
+import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
 
 /**
  * For each action type in an action group, make a simple
@@ -12,9 +13,8 @@ import { type } from '../../../shared/ngrx/type';
  */
 export const SearchFilterActionTypes = {
   COLLAPSE: type('dspace/search-filter/COLLAPSE'),
-  INITIAL_COLLAPSE: type('dspace/search-filter/INITIAL_COLLAPSE'),
+  INITIALIZE: type('dspace/search-filter/INITIALIZE'),
   EXPAND: type('dspace/search-filter/EXPAND'),
-  INITIAL_EXPAND: type('dspace/search-filter/INITIAL_EXPAND'),
   TOGGLE: type('dspace/search-filter/TOGGLE'),
   DECREMENT_PAGE: type('dspace/search-filter/DECREMENT_PAGE'),
   INCREMENT_PAGE: type('dspace/search-filter/INCREMENT_PAGE'),
@@ -66,15 +66,13 @@ export class SearchFilterToggleAction extends SearchFilterAction {
 /**
  * Used to set the initial state of a filter to collapsed
  */
-export class SearchFilterInitialCollapseAction extends SearchFilterAction {
-  type = SearchFilterActionTypes.INITIAL_COLLAPSE;
-}
-
-/**
- * Used to set the initial state of a filter to expanded
- */
-export class SearchFilterInitialExpandAction extends SearchFilterAction {
-  type = SearchFilterActionTypes.INITIAL_EXPAND;
+export class SearchFilterInitializeAction extends SearchFilterAction {
+  type = SearchFilterActionTypes.INITIALIZE;
+  initiallyExpanded;
+  constructor(filter: SearchFilterConfig) {
+    super(filter.name);
+    this.initiallyExpanded = filter.isOpenByDefault;
+  }
 }
 
 /**
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-filter.component.html
index 1013bf7e28..e2c128593f 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.html
@@ -1,7 +1,7 @@
-<div>
+<div *ngIf="active$ | async">
     <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 fas float-right"
-                                                                      [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}">
+                                                                      [ngClass]="(collapsed$ | async) ? 'fa-plus' : 'fa-minus'"></span></div>
+    <div [@slide]="(collapsed$ | async) ? 'collapsed' : 'expanded'"  (@slide.start)="startSlide($event)" (@slide.done)="finishSlide($event)" class="search-filter-wrapper" [ngClass]="{'closed' : closed}">
         <ds-search-facet-filter-wrapper [filterConfig]="filter"></ds-search-facet-filter-wrapper>
     </div>
 </div>
\ No newline at end of file
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts
index dcc01f2b46..eaf318655f 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.component.ts
@@ -1,11 +1,12 @@
-
-import { take } from 'rxjs/operators';
+import { filter, first, map, startWith, switchMap, take } from 'rxjs/operators';
 import { Component, Input, OnInit } from '@angular/core';
 import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
 import { SearchFilterService } from './search-filter.service';
-import { Observable } from 'rxjs';
+import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
 import { slide } from '../../../shared/animations/slide';
 import { isNotEmpty } from '../../../shared/empty.util';
+import { SearchService } from '../../search-service/search.service';
+import { SearchConfigurationService } from '../../search-service/search-configuration.service';
 
 @Component({
   selector: 'ds-search-filter',
@@ -26,9 +27,13 @@ export class SearchFilterComponent implements OnInit {
   /**
    * True when the filter is 100% collapsed in the UI
    */
-  collapsed;
+  closed = true;
+  collapsed$: Observable<boolean>;
+
+  selectedValues$: Observable<string[]>;
+  active$: Observable<boolean>;
 
-  constructor(private filterService: SearchFilterService) {
+  constructor(private filterService: SearchFilterService, private searchService: SearchService, private searchConfigService: SearchConfigurationService) {
   }
 
   /**
@@ -37,11 +42,13 @@ export class SearchFilterComponent implements OnInit {
    * Else, the filter should initially be collapsed
    */
   ngOnInit() {
-    this.getSelectedValues().pipe(take(1)).subscribe((isActive) => {
-      if (this.filter.isOpenByDefault || isNotEmpty(isActive)) {
-        this.initialExpand();
-      } else {
-        this.initialCollapse();
+    this.selectedValues$ = this.getSelectedValues();
+    this.active$ = this.isActive();
+    this.collapsed$ = this.isCollapsed();
+    this.initializeFilter();
+    this.selectedValues$.pipe(take(1)).subscribe((selectedValues) => {
+      if (isNotEmpty(selectedValues)) {
+        this.filterService.expand(this.filter.name);
       }
     });
   }
@@ -57,30 +64,21 @@ export class SearchFilterComponent implements OnInit {
    * Checks if the filter is currently collapsed
    * @returns {Observable<boolean>} Emits true when the current state of the filter is collapsed, false when it's expanded
    */
-  isCollapsed(): Observable<boolean> {
+  private isCollapsed(): Observable<boolean> {
     return this.filterService.isCollapsed(this.filter.name);
   }
 
   /**
-   *  Changes the initial state to collapsed
-   */
-  initialCollapse() {
-    this.filterService.initialCollapse(this.filter.name);
-    this.collapsed = true;
-  }
-
-  /**
-   *  Changes the initial state to expanded
+   *  Sets the initial state of the filter
    */
-  initialExpand() {
-    this.filterService.initialExpand(this.filter.name);
-    this.collapsed = false;
+  initializeFilter() {
+    this.filterService.initializeFilter(this.filter);
   }
 
   /**
    * @returns {Observable<string[]>} Emits a list of all values that are currently active for this filter
    */
-  getSelectedValues(): Observable<string[]> {
+  private getSelectedValues(): Observable<string[]> {
     return this.filterService.getSelectedValuesForFilter(this.filter);
   }
 
@@ -90,7 +88,7 @@ export class SearchFilterComponent implements OnInit {
    */
   finishSlide(event: any): void {
     if (event.fromState === 'collapsed') {
-      this.collapsed = false;
+      this.closed = false;
     }
   }
 
@@ -100,7 +98,32 @@ export class SearchFilterComponent implements OnInit {
    */
   startSlide(event: any): void {
     if (event.toState === 'collapsed') {
-      this.collapsed = true;
+      this.closed = true;
     }
   }
+
+  /**
+   * Check if a given filter is supposed to be shown or not
+   * @returns {Observable<boolean>} Emits true whenever a given filter config should be shown
+   */
+  private isActive(): Observable<boolean> {
+    return this.selectedValues$.pipe(
+      switchMap((isActive) => {
+        if (isNotEmpty(isActive)) {
+          return observableOf(true);
+        } else {
+          return this.searchConfigService.searchOptions.pipe(
+            first(),
+            switchMap((options) => {
+                return this.searchService.getFacetValuesFor(this.filter, 1, options).pipe(
+                  filter((RD) => !RD.isLoading),
+                  map((valuesRD) => {
+                    return valuesRD.payload.totalElements > 0
+                  }),)
+              }
+            ))
+        }
+      }),
+      startWith(true));
+  }
 }
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts b/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts
index f7e064fcc7..187bcd50d0 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.reducer.ts
@@ -1,5 +1,9 @@
-import { SearchFilterAction, SearchFilterActionTypes } from './search-filter.actions';
-import { isEmpty } from '../../../shared/empty.util';
+import {
+  SearchFilterAction,
+  SearchFilterActionTypes,
+  SearchFilterInitializeAction
+} from './search-filter.actions';
+import { isEmpty, isNotUndefined } from '../../../shared/empty.util';
 
 /**
  * Interface that represents the state for a single filters
@@ -28,27 +32,14 @@ export function filterReducer(state = initialState, action: SearchFilterAction):
 
   switch (action.type) {
 
-    case SearchFilterActionTypes.INITIAL_COLLAPSE: {
-      if (isEmpty(state) || isEmpty(state[action.filterName])) {
-        return Object.assign({}, state, {
-          [action.filterName]: {
-            filterCollapsed: true,
-            page: 1
-          }
-        });
-      }
-      return state;
-    }
-
-    case SearchFilterActionTypes.INITIAL_EXPAND: {
-      if (isEmpty(state) || isEmpty(state[action.filterName])) {
-        return Object.assign({}, state, {
-          [action.filterName]: {
-            filterCollapsed: false,
-            page: 1
-          }
-        });
-      }
+    case SearchFilterActionTypes.INITIALIZE: {
+      const initAction = (action as SearchFilterInitializeAction);
+      return Object.assign({}, state, {
+        [action.filterName]: {
+          filterCollapsed: !initAction.initiallyExpanded,
+          page: 1
+        }
+      });
       return state;
     }
 
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts
index 156e8d47ea..306f8cdb96 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.spec.ts
@@ -5,8 +5,7 @@ import {
   SearchFilterDecrementPageAction,
   SearchFilterExpandAction,
   SearchFilterIncrementPageAction,
-  SearchFilterInitialCollapseAction,
-  SearchFilterInitialExpandAction,
+  SearchFilterInitializeAction,
   SearchFilterResetPageAction,
   SearchFilterToggleAction
 } from './search-filter.actions';
@@ -62,25 +61,16 @@ describe('SearchFilterService', () => {
     service = new SearchFilterService(store, routeServiceStub);
   });
 
-  describe('when the initialCollapse method is triggered', () => {
+  describe('when the initializeFilter method is triggered', () => {
     beforeEach(() => {
-      service.initialCollapse(mockFilterConfig.name);
+      service.initializeFilter(mockFilterConfig);
     });
 
-    it('SearchFilterInitialCollapseAction should be dispatched to the store', () => {
-      expect(store.dispatch).toHaveBeenCalledWith(new SearchFilterInitialCollapseAction(mockFilterConfig.name));
+    it('SearchFilterInitializeAction should be dispatched to the store', () => {
+      expect(store.dispatch).toHaveBeenCalledWith(new SearchFilterInitializeAction(mockFilterConfig));
     });
   });
 
-  describe('when the initialExpand method is triggered', () => {
-    beforeEach(() => {
-      service.initialExpand(mockFilterConfig.name);
-    });
-
-    it('SearchFilterInitialExpandAction should be dispatched to the store', () => {
-      expect(store.dispatch).toHaveBeenCalledWith(new SearchFilterInitialExpandAction(mockFilterConfig.name));
-    });
-  });
 
   describe('when the collapse method is triggered', () => {
     beforeEach(() => {
diff --git a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts
index 34c34ee4cc..5ce1e8e647 100644
--- a/src/app/+search-page/search-filters/search-filter/search-filter.service.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-filter.service.ts
@@ -1,6 +1,6 @@
 import { combineLatest as observableCombineLatest, Observable } from 'rxjs';
 import { Injectable, InjectionToken } from '@angular/core';
-import { distinctUntilChanged, map } from 'rxjs/operators';
+import { distinctUntilChanged, map, tap } from 'rxjs/operators';
 import { SearchFiltersState, SearchFilterState } from './search-filter.reducer';
 import { createSelector, MemoizedSelector, select, Store } from '@ngrx/store';
 import {
@@ -8,8 +8,7 @@ import {
   SearchFilterDecrementPageAction,
   SearchFilterExpandAction,
   SearchFilterIncrementPageAction,
-  SearchFilterInitialCollapseAction,
-  SearchFilterInitialExpandAction,
+  SearchFilterInitializeAction,
   SearchFilterResetPageAction,
   SearchFilterToggleAction
 } from './search-filter.actions';
@@ -17,7 +16,9 @@ import { hasValue, isNotEmpty, } from '../../../shared/empty.util';
 import { SearchFilterConfig } from '../../search-service/search-filter-config.model';
 import { RouteService } from '../../../shared/services/route.service';
 import { Params } from '@angular/router';
-
+import { tag } from 'rxjs-spy/operators';
+import { create, detect } from "rxjs-spy";
+const spy = create();
 const filterStateSelector = (state: SearchFiltersState) => state.searchFilter;
 
 export const FILTER_CONFIG: InjectionToken<SearchFilterConfig> = new InjectionToken<SearchFilterConfig>('filterConfig');
@@ -58,16 +59,21 @@ export class SearchFilterService {
    * @returns {Observable<string[]>} Emits the active filters for the given filter configuration
    */
   getSelectedValuesForFilter(filterConfig: SearchFilterConfig): Observable<string[]> {
-    const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName);
+    const values$ = this.routeService.getQueryParameterValues(filterConfig.paramName).pipe(
+      tag("parameter")
+    );
     const prefixValues$ = this.routeService.getQueryParamsWithPrefix(filterConfig.paramName + '.').pipe(
-      map((params: Params) => [].concat(...Object.values(params)))
+      map((params: Params) => [].concat(...Object.values(params))),
+      tag("prefix-tag")
+
+
     );
+    spy.log();
+    detect('prefix-tag');
 
     return observableCombineLatest(values$, prefixValues$).pipe(
       map(([values, prefixValues]) => {
-        console.log('getSelectedValuesForFilter ', values, prefixValues);
-
-        if (isNotEmpty(values)) {
+          if (isNotEmpty(values)) {
             return values;
           }
           return prefixValues;
@@ -138,19 +144,11 @@ export class SearchFilterService {
   }
 
   /**
-   * Dispatches an initial collapse action to the store for a given filter
-   * @param {string} filterName The filter for which the action is dispatched
-   */
-  public initialCollapse(filterName: string): void {
-    this.store.dispatch(new SearchFilterInitialCollapseAction(filterName));
-  }
-
-  /**
-   * Dispatches an initial expand action to the store for a given filter
-   * @param {string} filterName The filter for which the action is dispatched
+   * Dispatches an initialize action to the store for a given filter
+   * @param {SearchFilterConfig} filter The filter for which the action is dispatched
    */
-  public initialExpand(filterName: string): void {
-    this.store.dispatch(new SearchFilterInitialExpandAction(filterName));
+  public initializeFilter(filter: SearchFilterConfig): void {
+    this.store.dispatch(new SearchFilterInitializeAction(filter));
   }
 
   /**
diff --git a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html
index 5434f0e0f4..3acc868a17 100644
--- a/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component.html
@@ -8,17 +8,8 @@
         </a>
         <ng-container *ngFor="let page of (filterValues$ | async)?.payload">
           <div [@facetLoad]="animationState">
-            <ng-container *ngFor="let value of page.page; trackBy: trackUpdate">
-                <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
-                   [routerLink]="[getSearchLink()]"
-                   [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge" >
-                    <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
-                    <span class="filter-value px-1">{{value.value}}</span>
-                    <span class="float-right filter-value-count ml-auto">
-                        <span class="badge badge-secondary badge-pill">{{value.count}}</span>
-                    </span>
-                </a>
-            </ng-container>
+            <ds-search-facet-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value">
+            </ds-search-facet-option>
           </div>
         </ng-container>
         <div class="clearfix toggle-more-filters">
diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html
index 1cc0556ed5..a30233ece3 100644
--- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.html
@@ -25,14 +25,7 @@
       <ng-container *ngFor="let page of (filterValues$ | async)?.payload">
         <div [@facetLoad]="animationState">
           <ng-container *ngFor="let value of page.page; trackBy: trackUpdate">
-                <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
-                   [routerLink]="[getSearchLink()]"
-                   [queryParams]="getChangeParams(value.value) | async" queryParamsHandling="merge">
-                    <span class="filter-value px-1">{{value.value}}</span>
-                    <span class="float-right filter-value-count ml-auto">
-                        <span class="badge badge-secondary badge-pill">{{value.count}}</span>
-                    </span>
-                </a>
+
             </ng-container>
           </div>
         </ng-container>
diff --git a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts
index 6cb04c6c1f..2b6797f5a1 100644
--- a/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts
+++ b/src/app/+search-page/search-filters/search-filter/search-range-filter/search-range-filter.component.ts
@@ -28,10 +28,9 @@ import { SearchConfigurationService } from '../../../search-service/search-confi
  * The route parameter 'id' is used to request the item it represents.
  * All fields of the item that should be displayed, are defined in its template.
  */
-const minSuffix = '.min';
-const maxSuffix = '.max';
+export const RANGE_FILTER_MIN_SUFFIX = '.min';
+export const RANGE_FILTER_MAX_SUFFIX = '.max';
 const dateFormats = ['YYYY', 'YYYY-MM', 'YYYY-MM-DD'];
-const rangeDelimiter = '-';
 
 @Component({
   selector: 'ds-search-range-filter',
@@ -85,8 +84,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
     super.ngOnInit();
     this.min = moment(this.filterConfig.minValue, dateFormats).year() || this.min;
     this.max = moment(this.filterConfig.maxValue, dateFormats).year() || this.max;
-    const iniMin = this.route.getQueryParameterValue(this.filterConfig.paramName + minSuffix).pipe(startWith(undefined));
-    const iniMax = this.route.getQueryParameterValue(this.filterConfig.paramName + maxSuffix).pipe(startWith(undefined));
+    const iniMin = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX).pipe(startWith(undefined));
+    const iniMax = this.route.getQueryParameterValue(this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX).pipe(startWith(undefined));
     this.sub = observableCombineLatest(iniMin, iniMax).pipe(
       map(([min, max]) => {
         const minimum = hasValue(min) ? min : this.min;
@@ -96,22 +95,7 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
     ).subscribe((minmax) => this.range = minmax);
   }
 
-  /**
-   * Calculates the parameters that should change if a given values for this range filter would be changed
-   * @param {string} value The values that are changed for this filter
-   * @returns {Observable<any>} The changed filter parameters
-   */
-  getChangeParams(value: string) {
-    const parts = value.split(rangeDelimiter);
-    const min = parts.length > 1 ? parts[0].trim() : value;
-    const max = parts.length > 1 ? parts[1].trim() : value;
-    return observableOf(
-      {
-        [this.filterConfig.paramName + minSuffix]: [min],
-        [this.filterConfig.paramName + maxSuffix]: [max],
-        page: 1
-      });
-  }
+
 
   /**
    * Submits new custom range values to the range filter from the widget
@@ -122,8 +106,8 @@ export class SearchRangeFilterComponent extends SearchFacetFilterComponent imple
     this.router.navigate([this.getSearchLink()], {
       queryParams:
         {
-          [this.filterConfig.paramName + minSuffix]: newMin,
-          [this.filterConfig.paramName + maxSuffix]: newMax
+          [this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX]: newMin,
+          [this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX]: newMax
         },
       queryParamsHandling: 'merge'
     });
diff --git a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html
index 32f6fe2153..45034507a2 100644
--- a/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html
+++ b/src/app/+search-page/search-filters/search-filter/search-text-filter/search-text-filter.component.html
@@ -10,15 +10,8 @@
           <div [@facetLoad]="animationState">
             <ng-container *ngFor="let page of filterValuesRD?.payload">
               <ng-container *ngFor="let value of page.page; trackBy: trackUpdate">
-                <a *ngIf="!(selectedValues | async).includes(value.value)" class="d-flex flex-row"
-                   [routerLink]="[getSearchLink()]"
-                   [queryParams]="getAddParams(value.value) | async" queryParamsHandling="merge" >
-                  <input type="checkbox" [checked]="false" class="my-1 align-self-stretch"/>
-                  <span class="filter-value px-1">{{value.value}}</span>
-                  <span class="float-right filter-value-count ml-auto">
-                          <span class="badge badge-secondary badge-pill">{{value.count}}</span>
-                      </span>
-                </a>
+                  <ds-search-facet-option *ngFor="let value of page.page; trackBy: trackUpdate" [filterConfig]="filterConfig" [filterValue]="value">
+                  </ds-search-facet-option>
               </ng-container>
             </ng-container>
           </div>
@@ -40,6 +33,5 @@
                           (submitSuggestion)="onSubmit($event)"
                           (clickSuggestion)="onClick($event)"
                           (findSuggestions)="findSuggestions($event)"
-                          ngDefaultControl
-    ></ds-input-suggestions>
+                          ngDefaultControl></ds-input-suggestions>
 </div>
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 de725f0958..ab2a96d752 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 @@
 <h3>{{"search.filters.head" | translate}}</h3>
 <div *ngIf="(filters | async)?.hasSucceeded">
     <div *ngFor="let filter of (filters | async)?.payload; trackBy: trackUpdate">
-        <ds-search-filter *ngIf="isActive(filter) | async" class="d-block mb-3 p-3" [filter]="filter"></ds-search-filter>
+        <ds-search-filter class="d-block mb-3 p-3" [filter]="filter"></ds-search-filter>
     </div>
 </div>
 <a class="btn btn-primary" [routerLink]="[getSearchLink()]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button">{{"search.filters.reset" | translate}}</a>
\ No newline at end of file
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 0d32df4867..1dd747e908 100644
--- a/src/app/+search-page/search-filters/search-filters.component.ts
+++ b/src/app/+search-page/search-filters/search-filters.component.ts
@@ -1,15 +1,13 @@
-import { Observable, of as observableOf } from 'rxjs';
+import { Observable } from 'rxjs';
 
-import { filter, first, map, mergeMap, startWith, switchMap, tap } from 'rxjs/operators';
+import { map } from 'rxjs/operators';
 import { Component } from '@angular/core';
 import { SearchService } from '../search-service/search.service';
 import { RemoteData } from '../../core/data/remote-data';
 import { SearchFilterConfig } from '../search-service/search-filter-config.model';
 import { SearchConfigurationService } from '../search-service/search-configuration.service';
-import { isNotEmpty } from '../../shared/empty.util';
 import { SearchFilterService } from './search-filter/search-filter.service';
 import { getSucceededRemoteData } from '../../core/shared/operators';
-import { FieldUpdate } from '../../core/data/object-updates/object-updates.reducer';
 
 @Component({
   selector: 'ds-search-filters',
@@ -53,32 +51,6 @@ export class SearchFiltersComponent {
     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<boolean>} Emits true whenever a given filter config should be shown
-   */
-  isActive(filterConfig: SearchFilterConfig): Observable<boolean> {
-    return this.filterService.getSelectedValuesForFilter(filterConfig).pipe(
-      switchMap((isActive) => {
-        console.log('selected fires');
-        if (isNotEmpty(isActive)) {
-          return observableOf(true);
-        } else {
-          return this.searchConfigService.searchOptions.pipe(
-            first(),
-            switchMap((options) => {
-                return this.searchService.getFacetValuesFor(filterConfig, 1, options).pipe(
-                  filter((RD) => !RD.isLoading),
-                  map((valuesRD) => {
-                    return valuesRD.payload.totalElements > 0
-                  }),)
-              }
-            ))
-        }
-      }), tap(t => console.log(t)), startWith(true));
-  }
-
   /**
    * Prevent unnecessary rerendering
    */
diff --git a/src/app/+search-page/search-page.component.ts b/src/app/+search-page/search-page.component.ts
index 816e3d67bf..0c572a3a84 100644
--- a/src/app/+search-page/search-page.component.ts
+++ b/src/app/+search-page/search-page.component.ts
@@ -62,7 +62,6 @@ export class SearchPageComponent implements OnInit {
   constructor(private service: SearchService,
               private sidebarService: SearchSidebarService,
               private windowService: HostWindowService,
-              private filterService: SearchFilterService,
               private searchConfigService: SearchConfigurationService) {
     this.isXsOrSm$ = this.windowService.isXsOrSm();
   }
diff --git a/src/app/+search-page/search-page.module.ts b/src/app/+search-page/search-page.module.ts
index 0c8a4ee306..b441367f1b 100644
--- a/src/app/+search-page/search-page.module.ts
+++ b/src/app/+search-page/search-page.module.ts
@@ -28,6 +28,9 @@ import { SearchFacetFilterWrapperComponent } from './search-filters/search-filte
 import { SearchBooleanFilterComponent } from './search-filters/search-filter/search-boolean-filter/search-boolean-filter.component';
 import { SearchHierarchyFilterComponent } from './search-filters/search-filter/search-hierarchy-filter/search-hierarchy-filter.component';
 import { SearchConfigurationService } from './search-service/search-configuration.service';
+import { SearchFacetOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-option/search-facet-option.component';
+import { SearchFacetSelectedOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-selected-option/search-facet-selected-option.component';
+import { SearchFacetRangeOptionComponent } from './search-filters/search-filter/search-facet-filter-options/search-facet-range-option/search-facet-range-option.component';
 
 const effects = [
   SearchSidebarEffects
@@ -63,6 +66,9 @@ const effects = [
     SearchTextFilterComponent,
     SearchHierarchyFilterComponent,
     SearchBooleanFilterComponent,
+    SearchFacetOptionComponent,
+    SearchFacetSelectedOptionComponent,
+    SearchFacetRangeOptionComponent
   ],
   providers: [
     SearchService,
@@ -82,6 +88,9 @@ const effects = [
     SearchTextFilterComponent,
     SearchHierarchyFilterComponent,
     SearchBooleanFilterComponent,
+    SearchFacetOptionComponent,
+    SearchFacetSelectedOptionComponent,
+    SearchFacetRangeOptionComponent
   ]
 })
 
diff --git a/src/app/shared/services/route.service.ts b/src/app/shared/services/route.service.ts
index 478d92c21e..b6c7747cfb 100644
--- a/src/app/shared/services/route.service.ts
+++ b/src/app/shared/services/route.service.ts
@@ -1,4 +1,4 @@
-import { distinctUntilChanged, map } from 'rxjs/operators';
+import { distinctUntilChanged, map, tap } from 'rxjs/operators';
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
 import {
@@ -6,6 +6,7 @@ import {
   Router,
 } from '@angular/router';
 import { isNotEmpty } from '../empty.util';
+import { detect } from 'rxjs-spy';
 
 @Injectable()
 export class RouteService {
@@ -14,6 +15,7 @@ export class RouteService {
   }
 
   getQueryParameterValues(paramName: string): Observable<string[]> {
+    console.log('called');
     return this.route.queryParamMap.pipe(
       map((params) => [...params.getAll(paramName)]),
       distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
@@ -44,6 +46,7 @@ export class RouteService {
   getQueryParamsWithPrefix(prefix: string): Observable<Params> {
     return this.route.queryParamMap.pipe(
       map((qparams) => {
+        console.log('map');
         const params = {};
         qparams.keys
           .filter((key) => key.startsWith(prefix))
@@ -52,6 +55,8 @@ export class RouteService {
           });
         return params;
       }),
-      distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)));
+      distinctUntilChanged((a, b) => { console.log('changed?', a, b, JSON.stringify(a) === JSON.stringify(b)); return JSON.stringify(a) === JSON.stringify(b)}),
+      tap((t) => console.log('changed'))
+    );
   }
 }
diff --git a/src/main.browser.ts b/src/main.browser.ts
index 8409a96485..7b0fbf9d65 100644
--- a/src/main.browser.ts
+++ b/src/main.browser.ts
@@ -12,6 +12,7 @@ import { BrowserAppModule } from './modules/app/browser-app.module';
 
 import { ENV_CONFIG } from './config';
 
+
 if (ENV_CONFIG.production) {
   enableProdMode();
 }
diff --git a/yarn.lock b/yarn.lock
index d71d9b9186..208ed60c2f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -243,6 +243,10 @@
     "@types/connect" "*"
     "@types/node" "*"
 
+"@types/circular-json@^0.4.0":
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/@types/circular-json/-/circular-json-0.4.0.tgz#7401f7e218cfe87ad4c43690da5658b9acaf51be"
+
 "@types/connect@*":
   version "3.4.32"
   resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28"
@@ -370,6 +374,10 @@
   dependencies:
     "@types/node" "*"
 
+"@types/stacktrace-js@^0.0.32":
+  version "0.0.32"
+  resolved "https://registry.yarnpkg.com/@types/stacktrace-js/-/stacktrace-js-0.0.32.tgz#d23e4a36a5073d39487fbea8234cc6186862d389"
+
 "@types/strip-bom@^3.0.0":
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2"
@@ -1600,6 +1608,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
+circular-json@^0.5.0:
+  version "0.5.9"
+  resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d"
+
 circular-json@^0.5.5:
   version "0.5.5"
   resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.5.tgz#64182ef359042d37cd8e767fc9de878b1e9447d3"
@@ -2605,6 +2617,12 @@ error-ex@^1.2.0, error-ex@^1.3.1:
   dependencies:
     is-arrayish "^0.2.1"
 
+error-stack-parser@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.2.tgz#4ae8dbaa2bf90a8b450707b9149dcabca135520d"
+  dependencies:
+    stackframe "^1.0.4"
+
 es-abstract@^1.4.3, es-abstract@^1.5.1:
   version "1.12.0"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
@@ -7237,6 +7255,16 @@ rx@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
 
+rxjs-spy@^7.5.1:
+  version "7.5.1"
+  resolved "https://registry.yarnpkg.com/rxjs-spy/-/rxjs-spy-7.5.1.tgz#1a9ef50bc8d7dd00d9ecf3c54c00929231eaf319"
+  dependencies:
+    "@types/circular-json" "^0.4.0"
+    "@types/stacktrace-js" "^0.0.32"
+    circular-json "^0.5.0"
+    error-stack-parser "^2.0.1"
+    stacktrace-gps "^3.0.2"
+
 rxjs@6.2.2, rxjs@^6.0.0, rxjs@^6.1.0:
   version "6.2.2"
   resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.2.tgz#eb75fa3c186ff5289907d06483a77884586e1cf9"
@@ -7681,6 +7709,10 @@ source-map@0.5.0:
   version "0.5.0"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86"
 
+source-map@0.5.6:
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
+
 source-map@0.7.3:
   version "0.7.3"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
@@ -7801,6 +7833,17 @@ ssri@^5.2.4:
   dependencies:
     safe-buffer "^5.1.1"
 
+stackframe@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.0.4.tgz#357b24a992f9427cba6b545d96a14ed2cbca187b"
+
+stacktrace-gps@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.2.tgz#33f8baa4467323ab2bd1816efa279942ba431ccc"
+  dependencies:
+    source-map "0.5.6"
+    stackframe "^1.0.4"
+
 static-extend@^0.1.1:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
-- 
GitLab