File
Implements
Metadata
selector |
range-facet |
styleUrls |
./facet-range.component.scss |
templateUrl |
./facet-range.component.html |
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Methods
Public
applyExactFilter
|
applyExactFilter()
|
|
|
Public
applyFilter
|
applyFilter()
|
|
Applies selected range filter by doing a search to the SearchService
|
Public
exactUpdate
|
exactUpdate()
|
|
Updates exact input to correct boundary
|
Public
maxUpdate
|
maxUpdate()
|
|
Updates max input to make sure it stays in the right boundary. Called each time the input is blurred.
|
Public
minUpdate
|
minUpdate()
|
|
Updates min input to make sure it stays in the right boundary. Called each time the input is blurred.
|
Public
openModal
|
openModal(content)
|
|
|
Public
switchFilter
|
switchFilter(filter)
|
|
|
exactFilterLabel
|
Type : string
|
|
exactInput
|
Type : FormControl
|
Default value : new FormControl()
|
|
facetId
|
Default value : this.idGenerator.getId()
|
|
maxInput
|
Type : FormControl
|
Default value : new FormControl()
|
|
minInput
|
Type : FormControl
|
Default value : new FormControl()
|
|
Public
modalService
|
Type : NgbModal
|
|
open
|
Default value : true
|
|
rangerFilterLabel
|
Type : string
|
|
import { Component, OnInit, Input, SimpleChanges, OnChanges } from '@angular/core';
import { FormControl } from '@angular/forms';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { LabelService } from 'src/app/core/services/label-service/label-service.service';
import { LoadingIndicatorService } from 'src/app/core/services/loading-indicator.service';
import { IdGeneratorService } from 'src/app/core/services/id-generator.service';
@Component({
selector: 'range-facet',
templateUrl: './facet-range.component.html',
styleUrls: ['./facet-range.component.scss']
})
export class RangeFacetComponent implements OnInit, OnChanges {
@Input() facet;
open = true;
minInput: FormControl = new FormControl();
maxInput: FormControl = new FormControl();
exactInput: FormControl = new FormControl();
min;
max;
facetId = this.idGenerator.getId(); // Id for the accordion
// Labels
facetName: string;
editLabel: string;
exactFilterLabel: string;
rangerFilterLabel: string;
applyLabel: string;
constructor(
public loadingService: LoadingIndicatorService,
public modalService: NgbModal,
public labelService: LabelService,
private idGenerator: IdGeneratorService
) {}
ngOnInit() {
this.labelService.getLabel(this.facet.displayName).then(res => this.facetName = res);
this.labelService.getLabel('facetRangeEditRange').then(res => this.editLabel = res);
this.labelService.getLabel('facetRangeExactFilter').then(res => this.exactFilterLabel = res);
this.labelService.getLabel('facetRangeRangeFilter').then(res => this.rangerFilterLabel = res);
this.labelService.getLabel('facetsApplyRange').then(res => this.applyLabel = res);
}
ngOnChanges(changes: SimpleChanges): void {
if (changes) {
// Make sure that input values are in range of min and max values
this.min = this.facet.properties.min;
this.max = this.facet.properties.max;
// If a range search has been made, set the input to the selected values.
if (this.facet.properties.selectedLower && this.facet.properties.selectedUpper) {
if (this.facet.properties.selectedLower >= this.min) { this.minInput.setValue(this.facet.properties.selectedLower); }
else { this.minInput.setValue(this.min); }
if (this.facet.properties.selectedUpper <= this.max) { this.maxInput.setValue(this.facet.properties.selectedUpper); }
else { this.maxInput.setValue(this.max); }
}
else if (this.facet.properties.selectExact) {
this.minInput.setValue(this.facet.properties.selectExact);
this.maxInput.setValue(this.facet.properties.selectExact);
}
else {
this.minInput.setValue(this.min);
this.maxInput.setValue(this.max);
}
}
}
/** Updates min input to make sure it stays in the right boundary. Called each time the input is blurred. */
public minUpdate() {
// Input can not be less than the minimum value of the search results.
if (this.minInput.value < this.facet.properties.min) {
this.minInput.setValue(this.facet.properties.min);
}
// Min input can not be larger than the max input and not larger than the maximum value of the search results.
if (this.minInput.value > this.maxInput.value || this.minInput.value > this.facet.properties.max) {
this.minInput.setValue(this.maxInput.value);
}
}
/** Updates max input to make sure it stays in the right boundary. Called each time the input is blurred. */
public maxUpdate() {
if (this.maxInput.value > this.facet.properties.max) {
this.maxInput.setValue(this.facet.properties.max);
}
if (this.maxInput.value < this.minInput.value || this.maxInput.value < this.facet.properties.min) {
this.maxInput.setValue(this.minInput.value);
}
}
/** Updates exact input to correct boundary */
public exactUpdate() {
if (this.exactInput.value < this.facet.properties.min) {
this.exactInput.setValue(this.facet.properties.min);
} else if (this.exactInput.value > this.facet.properties.max) {
this.exactInput.setValue(this.facet.properties.max);
}
}
/** Toggle facet */
public toggle() {
this.open = !this.open;
}
/** Applies selected range filter by doing a search to the SearchService */
public applyFilter() {
// Make sure input values are correct
this.minUpdate();
this.maxUpdate();
this.loadingService.show();
if (this.minInput.value === this.maxInput.value) {
// When min and max have are the same, do an exact search.
this.facet.selectExact(parseFloat(this.minInput.value));
} else {
// When min and max are different, search for a range.
this.facet.selectRange({
min: parseFloat(this.minInput.value),
max: parseFloat(this.maxInput.value)
});
}
this.modalService.dismissAll();
}
public applyExactFilter() {
this.loadingService.show();
this.facet.selectRange({
min: parseFloat(this.exactInput.value),
max: parseFloat(this.exactInput.value)
});
this.modalService.dismissAll();
}
public switchFilter(filter) {
this.modalService.dismissAll();
this.modalService.open(filter, {size: 'sm', centered: true});
}
public openModal(content) {
this.modalService.open(content, {size: 'sm', centered: true});
}
}
<div class="facet-range">
<div class="accordion" [id]="'range-facet' + facetId">
<div class="card">
<div class="card-header" [id]="facetName">
<a class="toggler" data-toggle="collapse" [href]="'#range-' + facetId" role="button" aria-expanded="true" [attr.aria-controls]="'range' + facetId">
<div>
<span class="mr-2">{{facetName | uppercase}}</span>
<span [innerHTML]="'['+ facet.properties.symbol + ']'">[]</span>
</div>
<i class="closed icon-chevronUp"></i>
<i class="open icon-chevronDown"></i>
</a>
</div>
<div class="collapse show" [id]="'range-' + facetId" [attr.aria-labelledby]="facetName" [attr.data-parent]="'#range-facet' + facetId">
<div class="card-body range-info">
<div class="current-range">
<span>{{ facet.properties.selectedLower || min }}</span>
<span>-</span>
<span>{{ facet.properties.selectedUpper || max }} {{facet.properties.unit}}</span>
</div>
<span class="edit-range" (click)="openModal(range)">{{ editLabel | uppercase }}</span>
</div>
</div>
</div>
</div>
<ng-template #range let-modal>
<div class="modal-header">
<h4 class="modal-title">{{facetName}}</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<input ngbAutofocus type="number" class="range-input" [formControl]="minInput" (blur)="minUpdate()" (keyup.enter)="applyFilter()">
<p>-</p>
<input type="number" class="range-input" [formControl]="maxInput" (blur)="maxUpdate()" (keyup.enter)="applyFilter()">
</div>
<div class="modal-footer">
<p (click)="switchFilter(exact)">{{exactFilterLabel}} <i class="icon-chevronLarge-next"></i></p>
<div class="apply-filter" (click)="applyFilter()">{{applyLabel | uppercase}}</div>
</div>
</ng-template>
<ng-template #exact let-modal>
<div class="modal-header">
<h4 class="modal-title">{{facetName}}</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<input ngbAutofocus type="number" class="range-input" [formControl]="exactInput" (blur)="minUpdate()" (keyup.enter)="applyExactFilter()">
</div>
<div class="modal-footer">
<p (click)="switchFilter(range)">{{rangerFilterLabel}} <i class="icon-chevronLarge-next"></i></p>
<div class="apply-filter" (click)="applyExactFilter()">{{applyLabel | uppercase}}</div>
</div>
</ng-template>
</div>
@import "src/app/styles/helpers";
.facet-range {
margin-bottom: calc-rem(2);
color: white;
background-color: $cool-grey;
.card {
background-color: inherit;
border: none;
&-header {
border: none;
background: transparent;
padding: calc-rem(20);
.toggler {
display: flex;
justify-content: space-between;
align-items: center;
color: $light-blue;
@include font-scale(14, uppercase);
letter-spacing: calc-rem(2);
&:hover { text-decoration: none; }
i { @include font-size(8); }
&[aria-expanded=true] .open {
display: none;
}
&[aria-expanded=false] .closed {
display: none;
}
}
}
&-body {
padding-top: calc-rem(10);
&.range-info {
color: white;
display: flex;
flex-direction: row;
justify-content: space-between;
.current-range {
span {
margin-right: calc-rem(5);
}
}
.edit-range {
color: $light-blue;
cursor: pointer;
@include font-size(14);
letter-spacing: calc-rem(0.4);
}
}
}
}
}
::ng-deep .modal-content {
z-index: 9999;
}
::ng-deep .modal-body {
display: flex;
flex-direction: column;
.range-input {
-moz-appearance: textfield;
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
p { text-align: center; }
}
::ng-deep .modal-footer {
display: flex;
flex-direction: column;
p {
cursor: pointer;
&:hover {
color: $cool-grey;
}
}
.apply-filter {
padding: 10px 0;
width: 100%;
text-align: center;
color: white;
background-color: $green;
cursor: pointer;
}
}
Legend
Html element with directive