Skip to content

Commit

Permalink
Merge pull request #898 from geonetwork/ME-fix-autocomplete
Browse files Browse the repository at this point in the history
feat(ui-inputs): Fix and extend autocomplete component
  • Loading branch information
jahow authored Jun 16, 2024
2 parents f6f2f02 + 14c8a46 commit 8f04e89
Show file tree
Hide file tree
Showing 17 changed files with 290 additions and 210 deletions.
3 changes: 2 additions & 1 deletion libs/feature/dataviz/src/lib/feature-dataviz.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { TableViewComponent } from './table-view/table-view.component'
import { ChartViewComponent } from './chart-view/chart-view.component'
import { TranslateModule } from '@ngx-translate/core'
import { UiWidgetsModule } from '@geonetwork-ui/ui/widgets'
import { PopupAlertComponent, UiWidgetsModule } from '@geonetwork-ui/ui/widgets'
import { UiInputsModule } from '@geonetwork-ui/ui/inputs'

@NgModule({
Expand All @@ -26,6 +26,7 @@ import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
TranslateModule,
ChartComponent,
UiInputsModule,
PopupAlertComponent,
],
declarations: [
GeoTableViewComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
[displayWithFn]="displayWithFn"
[action]="autoCompleteAction"
(itemSelected)="handleItemSelection($event)"
(inputSubmitted)="handleInputSubmission($event)"
(inputCleared)="handleInputCleared()"
[value]="searchInputValue$ | async"
[clearOnSelection]="true"
[minCharacterCount]="0"
[allowSubmit]="false"
></gn-ui-autocomplete>
<div class="flex gap-2 flex-wrap">
<gn-ui-badge
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import { CommonModule } from '@angular/common'
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core'
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { FormControl } from '@angular/forms'
import {
KeywordType,
ThesaurusModel,
} from '@geonetwork-ui/common/domain/model/thesaurus'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import {
AutocompleteComponent,
DropdownSelectorComponent,
UiInputsModule,
} from '@geonetwork-ui/ui/inputs'
import { UiWidgetsModule } from '@geonetwork-ui/ui/widgets'
import { Observable, map } from 'rxjs'
import { map } from 'rxjs'
import { Keyword } from '@geonetwork-ui/common/domain/model/record'

type AutocompleteItem = { title: string; value: Keyword }

@Component({
selector: 'gn-ui-form-field-keywords',
Expand All @@ -31,69 +24,34 @@ import { Observable, map } from 'rxjs'
UiInputsModule,
CommonModule,
UiWidgetsModule,
AutocompleteComponent,
],
})
export class FormFieldKeywordsComponent implements OnInit {
@Input() control: FormControl<any>
@Output() itemSelected = new EventEmitter<string>()
@Output() inputSubmitted = new EventEmitter<string>()
searchInputValue$: Observable<void | { title: string }>
allThesaurus$: Observable<any[]>
export class FormFieldKeywordsComponent {
@Input() control: FormControl<Keyword[]>

displayWithFn = (item) => {
if (item) {
return `${item?.title} (${item?.value?.name})`
}
return null
displayWithFn = (item: AutocompleteItem) => {
return `${item.title} (${item.value.thesaurus?.name})`
}

autoCompleteAction = (query: string) => {
const keywords$ = this.platformService.searchKeywords(query).pipe(
map((thesaurus) =>
thesaurus.map((thes) => {
return { title: thes.label, value: thes.thesaurus }
return this.platformService.searchKeywords(query).pipe(
map((keywords) =>
keywords.map((keyword) => {
return { title: keyword.label, value: keyword }
})
)
)

return keywords$
}

constructor(private platformService: PlatformServiceInterface) {}

ngOnInit(): void {
this.searchInputValue$ = this.autoCompleteAction('')[0]
}

// type: { title: string; value: ThesaurusModel }
handleItemSelection(item) {
this.addKeyword({
label: item.title,
thesaurus: item.value,
type: item.value.type,
})
}

handleInputSubmission(any: string) {
// Should there be an input submission?

if (this.inputSubmitted.observers.length > 0) {
this.inputSubmitted.emit(any)
} else {
// this.searchService.updateFilters({ any })
}
}

async handleInputCleared() {
this.autoCompleteAction('')
handleItemSelection(item: AutocompleteItem) {
this.addKeyword(item.value)
}

addKeyword(item: {
label: string
thesaurus: ThesaurusModel
type: KeywordType
}) {
const addedKeywords = [...this.control.value, item]
addKeyword(keyword: Keyword) {
const addedKeywords = [...this.control.value, keyword]

// remove duplicates from keyword
const filteredKeywords = addedKeywords.filter((value, index, self) => {
Expand Down
5 changes: 3 additions & 2 deletions libs/feature/record/src/lib/feature-record.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InjectionToken, NgModule } from '@angular/core'
import { NgModule } from '@angular/core'
import { CommonModule } from '@angular/common'
import { UiMapModule } from '@geonetwork-ui/ui/map'
import { StoreModule } from '@ngrx/store'
Expand All @@ -17,7 +17,7 @@ import {
} from './state/mdview.reducer'
import { MatTabsModule } from '@angular/material/tabs'
import { MatIconModule } from '@angular/material/icon'
import { UiWidgetsModule } from '@geonetwork-ui/ui/widgets'
import { PopupAlertComponent, UiWidgetsModule } from '@geonetwork-ui/ui/widgets'
import { TranslateModule } from '@ngx-translate/core'
import { ExternalViewerButtonComponent } from './external-viewer-button/external-viewer-button.component'
import { FeatureCatalogModule } from '@geonetwork-ui/feature/catalog'
Expand Down Expand Up @@ -52,6 +52,7 @@ import { DataViewShareComponent } from './data-view-share/data-view-share.compon
TranslateModule,
TableComponent,
FeatureDatavizModule,
PopupAlertComponent,
],
providers: [MdViewFacade],
exports: [
Expand Down
3 changes: 2 additions & 1 deletion libs/feature/search/src/lib/feature-search.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { SearchEffects } from './state/effects'
import { initialState, reducer, SEARCH_FEATURE_KEY } from './state/reducer'
import { ResultsHitsContainerComponent } from './results-hits-number/results-hits.container.component'
import { SearchStateContainerDirective } from './state/container/search-state.container.directive'
import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
import { AutocompleteComponent, UiInputsModule } from '@geonetwork-ui/ui/inputs'
import { NgModule } from '@angular/core'
import { UiElementsModule } from '@geonetwork-ui/ui/elements'
import { FavoriteStarComponent } from './favorites/favorite-star/favorite-star.component'
Expand Down Expand Up @@ -51,6 +51,7 @@ import { Gn4Repository } from '@geonetwork-ui/api/repository'
FacetsModule,
MatIconModule,
UiWidgetsModule,
AutocompleteComponent,
],
exports: [
SortByComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ describe('FuzzySearchComponent', () => {
useClass: RecordsRepositoryMock,
},
],
imports: [UiInputsModule, TranslateModule.forRoot()],
imports: [
AutocompleteComponent,
UiInputsModule,
TranslateModule.forRoot(),
],
}).compileComponents()

searchService = TestBed.inject(SearchService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
AutocompleteComponent,
AutocompleteItem,
} from '@geonetwork-ui/ui/inputs'
import { Observable, firstValueFrom } from 'rxjs'
import { firstValueFrom, Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { SearchFacade } from '../state/search.facade'
import { SearchService } from '../utils/service/search.service'
Expand All @@ -32,7 +32,7 @@ export class FuzzySearchComponent implements OnInit {
@Output() inputSubmitted = new EventEmitter<string>()
searchInputValue$: Observable<{ title: string }>

displayWithFn: (record: CatalogRecord) => string = (record) => record?.title
displayWithFn: (record: CatalogRecord) => string = (record) => record.title

autoCompleteAction = (query: string) =>
this.recordsRepository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
}
.clear-btn {
width: var(--input-height);
right: var(--input-height);
height: 100%;
}
.search-btn {
Expand Down
42 changes: 23 additions & 19 deletions libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,27 @@
[matAutocomplete]="auto"
(keyup.enter)="handleEnter(searchInput.value)"
/>
<button
type="button"
class="text-primary-lightest hover:text-primary hover:bg-gray-50 absolute transition-all duration-100 clear-btn inset-y-0"
*ngIf="searchInput.value"
aria-label="Clear"
(click)="clear()"
>
<mat-icon class="material-symbols-outlined">close</mat-icon>
</button>
<button
type="button"
class="text-primary bg-white hover:text-primary-darkest hover:bg-gray-100 border-gray-300 hover:border-gray-500 absolute transition-all duration-100 search-btn rounded-r inset-y-0 right-0"
aria-label="Trigger search"
(click)="handleClickSearch()"
>
<mat-icon class="material-symbols-outlined">search</mat-icon>
</button>
<div class="flex flex-row absolute inset-y-0 right-0">
<button
type="button"
class="text-primary-lightest hover:text-primary hover:bg-gray-50 transition-all duration-100 clear-btn"
*ngIf="searchInput.value"
aria-label="Clear"
(click)="clear()"
>
<mat-icon class="material-symbols-outlined">close</mat-icon>
</button>
<button
type="button"
class="text-primary bg-white hover:text-primary-darkest hover:bg-gray-100 border-gray-300 hover:border-gray-500 transition-all duration-100 search-btn rounded-r"
aria-label="Trigger search"
*ngIf="allowSubmit"
data-test="autocomplete-submit-btn"
(click)="handleClickSearch()"
>
<mat-icon class="material-symbols-outlined">search</mat-icon>
</button>
</div>
<gn-ui-popup-alert
*ngIf="error"
class="absolute mt-2 w-full top-[100%] left-0"
Expand All @@ -39,13 +43,13 @@
<mat-autocomplete
#auto="matAutocomplete"
(optionSelected)="handleSelection($event)"
[displayWith]="displayWithFn"
[displayWith]="displayWithFnInternal"
>
<mat-option
*ngFor="let suggestion of suggestions$ | async"
[value]="suggestion"
class="p-2 suggestion"
>
{{ displayWithFn(suggestion) }}
{{ displayWithFnInternal(suggestion) }}
</mat-option>
</mat-autocomplete>
Loading

0 comments on commit 8f04e89

Please sign in to comment.