Skip to content

Commit

Permalink
Merge d820991 into 6aa0ec4
Browse files Browse the repository at this point in the history
  • Loading branch information
LotteHofstede committed Mar 21, 2019
2 parents 6aa0ec4 + d820991 commit 383276d
Show file tree
Hide file tree
Showing 44 changed files with 652 additions and 425 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,9 @@
<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" [selectedValues$]="selectedValues$"></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; let i=index">
<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" [selectedValues$]="selectedValues$"></ds-search-facet-option>
</div>
</ng-container>
<div class="clearfix toggle-more-filters">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script src="search-facet-option.component.ts"></script><a *ngIf="isVisible | async" class="d-flex flex-row"
[routerLink]="[getSearchLink()]"
[queryParams]="addQueryParams" 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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { combineLatest as observableCombineLatest, Observable, Subscription } from 'rxjs';
import { map, take } from 'rxjs/operators';
import { Component, Input, OnDestroy, 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 { SearchConfigurationService } from '../../../../search-service/search-configuration.service';
import { hasValue } from '../../../../../shared/empty.util';

@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, OnDestroy {
/**
* A single value for this component
*/
@Input() filterValue: FacetValue;
@Input() filterConfig: SearchFilterConfig;
@Input() selectedValues$: Observable<string[]>;

isVisible: Observable<boolean>;

addQueryParams;
sub: Subscription;

constructor(protected searchService: SearchService,
protected filterService: SearchFilterService,
protected searchConfigService: SearchConfigurationService,
protected router: Router
) {
}

/**
* Initializes all observable instance variables and starts listening to them
*/
ngOnInit(): void {
this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
this.sub = observableCombineLatest(this.selectedValues$, this.searchConfigService.searchOptions)
.subscribe(([selectedValues, searchOptions]) => {
this.updateAddParams(selectedValues)
});
}

/**
* 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
*/
private updateAddParams(selectedValues: string[]): void {
this.addQueryParams = {
[this.filterConfig.paramName]: [...selectedValues, this.filterValue.value],
page: 1
};
}

ngOnDestroy(): void {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<a *ngIf="isVisible | async" class="d-flex flex-row"
[routerLink]="[getSearchLink()]"
[queryParams]="changeQueryParams" 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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Observable, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import { Component, Input, OnDestroy, 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';
import { SearchConfigurationService } from '../../../../search-service/search-configuration.service';
import { hasValue } from '../../../../../shared/empty.util';

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, OnDestroy {
/**
* A single value for this component
*/
@Input() filterValue: FacetValue;
@Input() filterConfig: SearchFilterConfig;

isVisible: Observable<boolean>;

changeQueryParams;
sub: Subscription;

constructor(protected searchService: SearchService,
protected filterService: SearchFilterService,
protected searchConfigService: SearchConfigurationService,
protected router: Router
) {
}

/**
* Initializes all observable instance variables and starts listening to them
*/
ngOnInit(): void {
this.isVisible = this.isChecked().pipe(map((checked: boolean) => !checked));
this.sub = this.searchConfigService.searchOptions.subscribe(() => {
this.updateChangeParams()
});
}

/**
* 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
*/
updateChangeParams(): void {
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;
this.changeQueryParams = {
[this.filterConfig.paramName + RANGE_FILTER_MIN_SUFFIX]: [min],
[this.filterConfig.paramName + RANGE_FILTER_MAX_SUFFIX]: [max],
page: 1
};
}

ngOnDestroy(): void {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<a class="d-flex flex-row"
[routerLink]="[getSearchLink()]"
[queryParams]="removeQueryParams" queryParamsHandling="merge">
<input type="checkbox" [checked]="true" class="my-1 align-self-stretch"/>
<span class="filter-value pl-1">{{selectedValue}}</span>
</a>
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {
combineLatest as observableCombineLatest,
Observable,
of as observableOf,
Subscription
} from 'rxjs';
import { delay, map } from 'rxjs/operators';
import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } 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 { hasValue } from '../../../../../shared/empty.util';
import { SearchOptions } from '../../../../search-options.model';
import { SearchConfigurationService } from '../../../../search-service/search-configuration.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, OnDestroy {
/**
* A single value for this component
*/
@Input() selectedValue: string;
@Input() filterConfig: SearchFilterConfig;

/**
* Emits the active values for this filter
*/
@Input() selectedValues$: Observable<string[]>;

removeQueryParams;
sub: Subscription;

constructor(protected searchService: SearchService,
protected filterService: SearchFilterService,
protected searchConfigService: SearchConfigurationService,
protected router: Router
) {
}

/**
* Initializes all observable instance variables and starts listening to them
*/
ngOnInit(): void {
this.sub = observableCombineLatest(this.selectedValues$, this.searchConfigService.searchOptions)
.subscribe(([selectedValues, searchOptions]) => {
this.updateRemoveParams(selectedValues)
});
}

/**
* @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 updateRemoveParams(selectedValues: string[]): void {
this.removeQueryParams = {
[this.filterConfig.paramName]: selectedValues.filter((v) => v !== this.selectedValue),
page: 1
};
}

ngOnDestroy(): void {
if (hasValue(this.sub)) {
this.sub.unsubscribe();
}
}
}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<ng-container *ngComponentOutlet="getSearchFilter(); injector: objectInjector;"></ng-container>
<ng-container *ngComponentOutlet="searchFilter injector: objectInjector;"></ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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
*/
Expand All @@ -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: [] }
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,6 @@ describe('SearchFacetFilterComponent', () => {
});
});

describe('when the getAddParams method is called wih a value', () => {
it('should return the selectedValue list with the new parameter value', () => {
const result = comp.getAddParams(value3);
result.subscribe((r) => expect(r[mockFilterConfig.paramName]).toEqual([value1, value2, value3]));
});
});

describe('when the getRemoveParams method is called wih a value', () => {
it('should return the selectedValue list with the parameter value left out', () => {
const result = comp.getRemoveParams(value1);
result.subscribe((r) => expect(r[mockFilterConfig.paramName]).toEqual([value2]));
});
});

describe('when the showMore method is called', () => {
beforeEach(() => {
spyOn(filterService, 'incrementPage');
Expand Down

0 comments on commit 383276d

Please sign in to comment.