src/app/modules/ontology-exploration/ontology-search/ontology-search.component.ts
Componenet for searching the Ontology nodes.
OnInit
changeDetection | ChangeDetectionStrategy.OnPush |
selector | ccf-ontology-search |
styleUrls | ./ontology-search.component.scss |
templateUrl | ./ontology-search.component.html |
Properties |
Methods |
Inputs |
Outputs |
constructor(ontologyService: OntologySearchService, ga: GoogleAnalyticsService)
|
||||||||||||
Creates an instance of ontology search component.
Parameters :
|
placeholderText | |
Type : string
|
|
selected | |
Type : EventEmitter
|
|
Output event-emitter which emits the id of the OntologyTreeNode whose label was selected by the user in the search-results |
displayFormatter | ||||||||
displayFormatter(option?: SearchResult)
|
||||||||
A formatter function to enable different display and selected value
Parameters :
Returns :
string
a part of the search result entry to be displayed as a display value |
onSelect | ||||||||
onSelect(event: MatAutocompleteSelectedEvent)
|
||||||||
Callback function triggered when the user selects a value from search results
Parameters :
Returns :
void
|
sortBySynonymResult | ||||||||||||
sortBySynonymResult(this: void, entry: SearchResult)
|
||||||||||||
Sorts by results which have synonyms
Parameters :
Returns :
number
1 or -1 |
sortLexically | ||||||||||||
sortLexically(this: void, entry: SearchResult)
|
||||||||||||
Sorts lexically
Parameters :
Returns :
string
lower case value of node label |
autoCompleteOpen |
Default value : false
|
Determines if autocomplete is open or close. |
filteredResults$ |
Type : Observable<SearchResult[]>
|
Observable which provides the filtered search results |
formControl |
Default value : new UntypedFormControl('')
|
Instance of FormControl - tracks the value and validation status of an individual form control |
Public ontologyService |
Type : OntologySearchService
|
instance of searchService which provides all the search functionality
|
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { OntologyTreeNode } from 'ccf-database';
import { get, sortBy } from 'lodash';
import { GoogleAnalyticsService } from 'ngx-google-analytics';
import { Observable } from 'rxjs';
import { filter, map, startWith, switchMap } from 'rxjs/operators';
import { OntologySearchService, SearchResult } from '../../../core/services/ontology-search/ontology-search.service';
/**
* Componenet for searching the Ontology nodes.
*/
@Component({
selector: 'ccf-ontology-search',
templateUrl: './ontology-search.component.html',
styleUrls: ['./ontology-search.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OntologySearchComponent implements OnInit {
@Input() placeholderText!: string;
/**
* Output event-emitter which emits the id of the OntologyTreeNode whose label was
* selected by the user in the search-results
*/
@Output() readonly selected = new EventEmitter<OntologyTreeNode>();
/**
* Instance of FormControl - tracks the value and validation status of an individual form control
*/
formControl = new UntypedFormControl('');
/**
* Determines if autocomplete is open or close.
*/
autoCompleteOpen = false;
/**
* Observable which provides the filtered search results
*/
filteredResults$!: Observable<SearchResult[]>;
/**
* Creates an instance of ontology search component.
*
* @param ontologyService instance of searchService which provides all the search functionality
* @param ga Analytics service
*/
constructor(
public ontologyService: OntologySearchService,
private readonly ga: GoogleAnalyticsService,
) {}
/**
* on-init lifecycle hook for this component -
* gets the searched value from the view, sends it to the filter function in the OntologyService,
* and gets the search results from the service
*/
ngOnInit(): void {
const valueChanges = this.formControl.valueChanges as Observable<string>;
this.filteredResults$ = valueChanges.pipe(
filter((value) => typeof value === 'string'),
startWith(''),
switchMap((value) => this.ontologyService.filter(value)),
map((searchResults) => sortBy(searchResults, [this.sortBySynonymResult, 'index', this.sortLexically])),
);
}
/**
* A formatter function to enable different display and selected value
*
* @param option a search result entry
* @returns a part of the search result entry to be displayed as a display value
*/
displayFormatter(option?: SearchResult): string {
return (option?.displayLabel ?? []).join('');
}
/**
* Sorts by results which have synonyms
*
* @param entry search result entry
* @returns 1 or -1
*/
sortBySynonymResult(this: void, entry: SearchResult): number {
return entry.displayLabel.join().includes('(') ? 1 : -1;
}
/**
* Sorts lexically
*
* @param entry search result entry
* @returns lower case value of node label
*/
sortLexically(this: void, entry: SearchResult): string {
return entry.node.label.toLowerCase();
}
/**
* Callback function triggered when the user selects a value from search results
*
* @param event instance of MatAutocompleteSelectedEvent
*/
onSelect(event: MatAutocompleteSelectedEvent): void {
const node = get(event, ['option', 'value', 'node']) as OntologyTreeNode;
if (node) {
this.ga.event('search', 'ontology_search', node.id);
this.selected.emit(node);
this.formControl.reset();
}
}
}
<form class="ccf-ontology-search" [class.autocomplete-open]="autoCompleteOpen">
<mat-form-field appearance="outline" class="field" subscriptSizing="dynamic">
<mat-icon matPrefix color="primary" class="search">search</mat-icon>
<input
class="input"
type="text"
[placeholder]="placeholderText"
matInput
[formControl]="formControl"
[matAutocomplete]="autocomplete"
/>
<mat-autocomplete
class="ccf-ontology-search detached autocomplete"
[displayWith]="displayFormatter"
(optionSelected)="onSelect($event)"
(opened)="autoCompleteOpen = true"
(closed)="autoCompleteOpen = false"
#autocomplete
>
<div class="results-container">
<mat-option *ngFor="let option of filteredResults$ | async" [value]="option">
<span class="prefix">{{ option.displayLabel[0] }}</span>
<span class="search-term">{{ option.displayLabel[1] }}</span>
<span class="suffix">{{ option.displayLabel[2] }}</span>
</mat-option>
</div>
</mat-autocomplete>
</mat-form-field>
</form>
./ontology-search.component.scss
.ccf-ontology-search {
width: 100%;
.field {
width: 100%;
padding-bottom: 1.34375em;
font-size: inherit;
line-height: 1.125;
letter-spacing: normal;
::ng-deep .mat-mdc-text-field-wrapper {
margin: 0;
height: 2.75rem;
.mat-mdc-form-field-flex {
align-items: center;
height: 2.75rem;
.mat-mdc-form-field-infix {
padding: 1rem 0;
input {
margin-left: 0.4rem;
}
}
.mat-mdc-form-field-icon-prefix {
padding: 0;
}
mat-icon {
padding-right: 0;
}
}
}
}
}
::ng-deep .ccf-ontology-search.detached {
border: 0.125rem solid;
border-top: none;
border-radius: 0 0 0.25rem 0.25rem;
max-height: 18rem;
padding: 0;
box-shadow: none;
.results-container {
width: 23.75rem;
margin-bottom: 1rem;
overflow: auto;
max-height: 15rem;
scrollbar-width: thin;
mat-option {
min-height: 1.5rem;
font-size: 1rem;
font-weight: 500;
.search-term {
text-decoration: underline;
}
}
}
}
.autocomplete-open {
::ng-deep .mdc-notched-outline {
.mdc-notched-outline__leading {
border-radius: 0.25rem 0 0 0;
border-bottom: none;
}
.mdc-notched-outline__trailing {
border-radius: 0 0.25rem 0 0;
border-bottom: none;
}
}
}