Skip to content

Commit

Permalink
feat(search-results): Display more results (#544)
Browse files Browse the repository at this point in the history
* feat(search): Display more results function (iCherche & iLayer)

* feat(search): Display more results function (iCherche & iLayer)

* lasts modifs on allowing to display more results

* Update search-results.component.ts

* feat(search): Display more results function (iCherche & iLayer)

* lasts modifs on allowing to display more results

* Update search-results.component.ts

* display more results lasts modifs

* display more results lasts modifs (get by source id)

* Update search-results.component.ts

Co-authored-by: Marc-André Barbeau <[email protected]>
  • Loading branch information
PhilippeLafreniere18 and mbarbeau committed Jan 15, 2020
1 parent 8b7ca22 commit fce0b94
Show file tree
Hide file tree
Showing 14 changed files with 131 additions and 26 deletions.
6 changes: 4 additions & 2 deletions demo/src/app/geo/search/search.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@
<igo-search-bar
(pointerSummaryEnabled)="onPointerSummaryEnabledChange($event)"
[searchSettings]="true"
(change)="onSearchTermChange($event)"
(searchTermChange)="onSearchTermChange($event)"
(search)="onSearch($event)"
(clearFeature)="removeFeatureFromMap()">
</igo-search-bar>

<igo-search-results
[store]="searchStore"
[term]="term"
placeholder="false"
(resultFocus)="onResultFocus($event)"
(resultSelect)="onResultFocus($event)">
(resultSelect)="onResultFocus($event)"
(moreResults)="onSearch($event)">
<ng-template #igoSearchItemToolbar let-result="result">
<igo-search-add-button
[map]="map"
Expand Down
7 changes: 5 additions & 2 deletions demo/src/app/geo/search/search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export class AppSearchComponent implements OnInit, OnDestroy {

public lonlat;
public mapProjection: string;
public term: string;

get searchStore(): EntityStore<SearchResult> {
return this.searchState.store;
Expand Down Expand Up @@ -95,8 +96,10 @@ export class AppSearchComponent implements OnInit, OnDestroy {
this.igoSearchPointerSummaryEnabled = value;
}

onSearchTermChange(term?: string) {
if (term === undefined || term === '') {
onSearchTermChange(term = '') {
this.term = term;
const termWithoutHashtag = term.replace(/(#[^\s]*)/g, '').trim();
if (termWithoutHashtag.length < 2) {
this.searchStore.clear();
this.selectedFeature = undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@

</igo-search-results-item>
</ng-template>
<span class="moreResults mat-typography" *ngIf="isMoreResults(group)" (click)="displayMoreResults(group)">
<u>{{ 'igo.geo.search.displayMoreResults' | translate }}</u>
</span>
</ng-template>

</ng-template>

</igo-list>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.moreResults {
cursor: pointer;
color: blue;
float: right;
margin-right: 10px;
margin-top: 5px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ import { debounce, map } from 'rxjs/operators';

import { EntityStore, EntityStoreWatcher } from '@igo2/common';

import { SearchResult } from '../shared/search.interfaces';
import { SearchSource } from '../shared/sources/source';
import { IgoMap } from '../../map';

import { TextSearchOptions } from '../shared/sources/source.interfaces';
import { SearchService } from '../shared/search.service';
import { SearchResult, Research } from '../shared/search.interfaces';
import { SearchSource } from '../shared/sources/source';

export enum SearchResultMode {
Grouped = 'grouped',
Flat = 'flat'
Expand All @@ -32,6 +35,7 @@ export enum SearchResultMode {
@Component({
selector: 'igo-search-results',
templateUrl: './search-results.component.html',
styleUrls: ['./search-results.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SearchResultsComponent implements OnInit, OnDestroy {
Expand All @@ -46,6 +50,8 @@ export class SearchResultsComponent implements OnInit, OnDestroy {
*/
private watcher: EntityStoreWatcher<SearchResult>;

public pageIterator: {sourceId: string}[] = [];

@Input() map: IgoMap;

/**
Expand All @@ -68,6 +74,19 @@ export class SearchResultsComponent implements OnInit, OnDestroy {
*/
@Input() withZoomButton = false;

/**
* Search term
*/
@Input()
get term(): string {
return this._term;
}
set term(value: string) {
this._term = value;
this.pageIterator = [];
}
public _term: string;

/**
* Event emitted when a result is focused
*/
Expand All @@ -83,6 +102,14 @@ export class SearchResultsComponent implements OnInit, OnDestroy {
*/
@Output() resultSelect = new EventEmitter<SearchResult>();

/**
* Event emitted when a research is completed after displaying more results is clicked
*/
@Output() moreResults = new EventEmitter<{
research: Research;
results: SearchResult[];
}>();

/**
* Events emitted when a result is focus or unfocus by mouse event
*/
Expand All @@ -101,7 +128,8 @@ export class SearchResultsComponent implements OnInit, OnDestroy {
{source: SearchSource; results: SearchResult[]}[]
>;

constructor(private cdRef: ChangeDetectorRef) {}
constructor(private cdRef: ChangeDetectorRef,
private searchService: SearchService) {}

/**
* Bind the search results store to the watcher
Expand Down Expand Up @@ -203,7 +231,30 @@ export class SearchResultsComponent implements OnInit, OnDestroy {
});

return Array.from(grouped.keys()).map((source: SearchSource) => {
if (this.pageIterator[source.getId()] === undefined) {
this.pageIterator[source.getId()] = 1
};
return {source, results: grouped.get(source)};
});
}

isMoreResults(group: {source: SearchSource; results: SearchResult[]}) {
return group.results && group.results[group.results.length - 1].meta.nextPage === true;
}

displayMoreResults(group: {source: SearchSource; results: SearchResult[]}) {
const options: TextSearchOptions = {
sourceId: group.source.getId(),
page: ++this.pageIterator[group.source.getId()]
};

const researches = this.searchService.search(this.term, options);
researches.map(research => {
research.request.subscribe((results: SearchResult[]) => {
const newResults = group.results.concat(results);
this.moreResults.emit({research, results: newResults});
});
});
return;
}
}
1 change: 1 addition & 0 deletions packages/geo/src/lib/search/shared/search.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ export interface SearchResult<T = { [key: string]: any }> {
title: string;
titleHtml?: string;
icon: string;
nextPage?: boolean;
};
}
9 changes: 7 additions & 2 deletions packages/geo/src/lib/search/shared/search.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,19 @@ export class SearchService {
.getMap()
.viewController.getExtent('EPSG:4326');

let sources = this.searchSourceService.getEnabledSources();
let sources;

if (options.getEnabledOnly || options.getEnabledOnly === undefined) {
sources = this.searchSourceService.getEnabledSources();
} else {
sources = this.searchSourceService.getSources();
}
if (options.searchType) {

if (options.sourceId) {
sources = sources.filter(
source => source.getId() === options.sourceId
);
} else if (options.searchType) {
sources = sources.filter(
source => source.getType() === options.searchType
);
Expand Down
11 changes: 7 additions & 4 deletions packages/geo/src/lib/search/shared/sources/icherche.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ export class IChercheSearchSource extends SearchSource implements TextSearch {
geometry: true,
bbox: true,
icon: true,
page: options.page,
type:
'adresses,codes-postaux,municipalites,mrc,regadmin,lieux,entreprises,bornes-sumi'
},
Expand All @@ -351,16 +352,16 @@ export class IChercheSearchSource extends SearchSource implements TextSearch {
queryParams.type = 'lieux';
}

return new HttpParams({ fromObject: queryParams });
return new HttpParams({ fromObject: ObjectUtils.removeUndefined(queryParams) });
}

private extractResults(response: IChercheResponse): SearchResult<Feature>[] {
return response.features.map((data: IChercheData) => {
return this.formatter.formatResult(this.dataToResult(data));
return this.formatter.formatResult(this.dataToResult(data, response));
});
}

private dataToResult(data: IChercheData): SearchResult<Feature> {
private dataToResult(data: IChercheData, response?: IChercheResponse): SearchResult<Feature> {
const properties = this.computeProperties(data);
const id = [this.getId(), properties.type, properties.code].join('.');

Expand Down Expand Up @@ -390,7 +391,9 @@ export class IChercheSearchSource extends SearchSource implements TextSearch {
id,
title: data.properties.nom,
titleHtml: titleHtml + subtitleHtml + subtitleHtml2,
icon: data.icon || 'map-marker'
icon: data.icon || 'map-marker',
nextPage: (response.features.length % Number(this.options.params.limit) !== 0
|| Number(this.options.params.page) > 10) ? false : true
}
};
}
Expand Down
15 changes: 9 additions & 6 deletions packages/geo/src/lib/search/shared/sources/ilayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Observable, BehaviorSubject, of } from 'rxjs';
import { map } from 'rxjs/operators';

import { LanguageService } from '@igo2/core';
import { ObjectUtils } from '@igo2/utils';

import { getResolutionFromScale } from '../../../map/shared/map.utils';
import { LAYER } from '../../../layer';
Expand Down Expand Up @@ -174,14 +175,15 @@ export class ILayerSearchSource extends SearchSource implements TextSearch {
options: TextSearchOptions
): HttpParams {
return new HttpParams({
fromObject: Object.assign(
fromObject: ObjectUtils.removeUndefined(Object.assign(
{
q: this.computeTerm(term)
q: this.computeTerm(term),
page: options.page
},
this.params,
options.params || {}
)
});
)});
}

/**
Expand All @@ -205,10 +207,10 @@ export class ILayerSearchSource extends SearchSource implements TextSearch {
private extractResults(
response: ILayerServiceResponse
): SearchResult<ILayerItemResponse>[] {
return response.items.map((data: ILayerData) => this.dataToResult(data));
return response.items.map((data: ILayerData) => this.dataToResult(data, response));
}

private dataToResult(data: ILayerData): SearchResult<ILayerItemResponse> {
private dataToResult(data: ILayerData, response?: ILayerServiceResponse): SearchResult<ILayerItemResponse> {
const layerOptions = this.computeLayerOptions(data);

const titleHtml = data.highlight.title || data.properties.title;
Expand All @@ -224,7 +226,8 @@ export class ILayerSearchSource extends SearchSource implements TextSearch {
id: [this.getId(), data.properties.id].join('.'),
title: data.properties.title,
titleHtml: titleHtml + subtitleHtml,
icon: data.properties.type === 'Layer' ? 'layers' : 'map'
icon: data.properties.type === 'Layer' ? 'layers' : 'map',
nextPage: (response.items.length % Number(this.options.params.limit) !== 0) ? false : true
},
data: layerOptions
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export interface TextSearchOptions {
searchType?: 'Feature' | 'Layer'; // refer to search.enum.ts SEARCH_TYPES = [FEATURE, LAYER];
getEnabledOnly?: boolean;
extent?: [number, number, number, number];
page?: number;
sourceId?: string;
}

export interface ReverseSearchOptions {
Expand Down
3 changes: 2 additions & 1 deletion packages/geo/src/locale/en.geo.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@
"true": "Yes",
"false": "No"
}
}
},
"displayMoreResults": "Display more results"
},
"geometry": {
"geometry": "Geometry",
Expand Down
3 changes: 2 additions & 1 deletion packages/geo/src/locale/fr.geo.json
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@
"true": "Oui",
"false": "Non"
}
}
},
"displayMoreResults": "Afficher plus de résultats"
},
"geometry": {
"geometry": "Geometrie",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ <h4>{{ 'igo.integration.searchResultsTool.noResults' | translate }}</h4>
<igo-search-results
[store]="store"
[showIcons]="showIcons"
[term]="term"
placeholder="false"
(resultFocus)="onResultFocus($event)"
(resultSelect)="onResultFocus($event)">
(resultSelect)="onResultFocus($event)"
(moreResults)="onSearch($event)">
<ng-template #igoSearchItemToolbar let-result="result">
<igo-search-add-button
[map]="map"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, ChangeDetectionStrategy, Input } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { Component, ChangeDetectionStrategy, Input, OnInit } from '@angular/core';
import { Observable, BehaviorSubject, Subscription } from 'rxjs';
import { map } from 'rxjs/operators';
import olFormatGeoJSON from 'ol/format/GeoJSON';

Expand All @@ -19,7 +19,8 @@ import {
LAYER,
SearchResult,
IgoMap,
moveToOlFeatures
moveToOlFeatures,
Research
} from '@igo2/geo';

import { MapState } from '../../map/map.state';
Expand All @@ -39,7 +40,7 @@ import { SearchState } from '../search.state';
templateUrl: './search-results-tool.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class SearchResultsToolComponent {
export class SearchResultsToolComponent implements OnInit {
/**
* to show hide results icons
*/
Expand Down Expand Up @@ -80,6 +81,9 @@ export class SearchResultsToolComponent {

public feature: Feature;

public term = '';
private searchTerm$$: Subscription;

public topPanelState$ = new BehaviorSubject<FlexibleState>('initial');

@Input()
Expand All @@ -98,6 +102,13 @@ export class SearchResultsToolComponent {
private searchState: SearchState
) {}

ngOnInit() {
this.searchTerm$$ = this.searchState.searchTerm$.subscribe((searchTerm: string) => {
if (searchTerm !== undefined && searchTerm !== null) {
this.term = searchTerm;
}
});
}
/**
* Try to add a feature to the map when it's being focused
* @internal
Expand All @@ -123,6 +134,15 @@ export class SearchResultsToolComponent {
}
}

onSearch(event: { research: Research; results: SearchResult[] }) {
const results = event.results;
this.store.state.updateAll({ focused: false, selected: false });
const newResults = this.store.entities$.value
.filter((result: SearchResult) => result.source !== event.research.source)
.concat(results);
this.store.load(newResults);
}

toggleTopPanel() {
if (this.topPanelState === 'expanded') {
this.topPanelState = 'collapsed';
Expand Down

0 comments on commit fce0b94

Please sign in to comment.