Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display more results #544

Merged
merged 12 commits into from
Jan 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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