Newer
Older
id="geocoder-container"
:class="{ isExpanded }"
title="Rechercher une adresse"
<!-- internal-search should be disabled to avoid filtering options, which is done by the api calls anyway https://stackoverflow.com/questions/57813170/vue-multi-select-not-showing-all-the-options -->
<!-- otherwise approximate results are not shown (cannot explain why though) -->
ref="multiselect"
:options-limit="limit"
:internal-search="false"
track-by="id"
label="label"
:show-labels="false"
:reset-after="true"
select-label=""
selected-label=""
deselect-label=""
:searchable="true"
:placeholder="placeholder"
:show-no-results="true"
:loading="loading"
:clear-on-select="false"
:preserve-search="true"
@search-change="search"
@select="select"
@open="retrievePreviousPlaces"
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@close="close"
>
<template
slot="option"
slot-scope="props"
>
<div class="option__desc">
<span class="option__title">{{ props.option.label }}</span>
</div>
</template>
<template slot="clear">
<div
v-if="selection"
class="multiselect__clear"
@click.prevent.stop="selection = null"
>
<i class="close icon" />
</div>
</template>
<span slot="noResult">
Aucun résultat.
</span>
<span slot="noOptions">
Saisissez les premiers caractères ...
</span>
</Multiselect>
<div style="display: none;">
<div
id="marker"
title="Marker"
/>
</div>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import axios from 'axios';
import mapService from '@/services/map-service';
const apiAdressAxios = axios.create({
baseURL: 'https://api-adresse.data.gouv.fr',
withCredentials: false,
});
limit: 10,
selection: null,
text: null,
selectedAddress: null,
addresses: [],
resultats: [],
placeholder: 'Rechercher une adresse ...',
isExpanded: false
mounted() {
this.addressTextChange = new Subject();
this.addressTextChange.pipe(debounceTime(200)).subscribe((res) => this.getAddresses(res));
},
toggleGeocoder() {
this.isExpanded = !this.isExpanded;
if (this.isExpanded) {
this.retrievePreviousPlaces();
this.$nextTick(()=> this.$refs.multiselect.activate());
}
},
if (query.length < 3) {
this.addresses = [];
return;
}
const coords = mapService.getMapCenter();
let url = `https://api-adresse.data.gouv.fr/search/?q=${query}&limit=${this.limit}`;
if (coords) url += `&lon=${coords[0]}&lat=${coords[1]}`;
apiAdressAxios.get(url)
this.resultats = retour.data.features;
this.addresses = retour.data.features.map(x=>x.properties);
selectAddresse(event) {
this.selectedAddress = event;
if (this.selectedAddress !== null && this.selectedAddress.geometry) {
let zoomlevel = 14;
const { type } = this.selectedAddress.properties;
if (type === 'housenumber') {
zoomlevel = 19;
} else if (type === 'street') {
zoomlevel = 16;
} else if (type === 'locality') {
zoomlevel = 16;
}
// On ajoute un point pour localiser la ville
mapService.addOverlay(this.selectedAddress.geometry.coordinates, zoomlevel);
// On enregistre l'adresse sélectionné pour le proposer à la prochaine recherche
this.setLocalstorageSelectedAdress(this.selectedAddress);
search(text) {
this.text = text;
this.addressTextChange.next(this.text);
},
this.selectAddresse(this.resultats.find(x=>x.properties.label === e.label));
close() {
this.$emit('close', this.selection);
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
},
setLocalstorageSelectedAdress(newAdress) {
let selectedAdresses = JSON.parse(localStorage.getItem('geocontrib-selected-adresses'));
selectedAdresses = Array.isArray(selectedAdresses) ? selectedAdresses : [];
selectedAdresses = [ newAdress, ...selectedAdresses ];
const uniqueLabels = [...new Set(selectedAdresses.map(el => el.properties.label))];
const uniqueAdresses = uniqueLabels.map((label) => {
return selectedAdresses.find(adress => adress.properties.label === label);
});
localStorage.setItem(
'geocontrib-selected-adresses',
JSON.stringify(uniqueAdresses.slice(0, 5))
);
},
getLocalstorageSelectedAdress() {
return JSON.parse(localStorage.getItem('geocontrib-selected-adresses')) || [];
},
retrievePreviousPlaces() {
const previousAdresses = this.getLocalstorageSelectedAdress();
if (previousAdresses.length > 0) {
this.addresses = previousAdresses.map(x=>x.properties);
this.resultats = previousAdresses;
}
},
<style lang="less">
width: 14px;
height: 14px;
border: 2px solid #fff;
border-radius: 7px;
background-color: #3399CC;
#geocoder-container {
right: 6px;
// each button have (more or less depends on borders) .5em space between
// zoom buttons are 60px high, geolocation and full screen button is 34px high with borders
top: calc(1.6em + 60px + 34px + 34px);
z-index: 999;
border: 2px solid rgba(0,0,0,.2);
background-clip: padding-box;
padding: 0;
border-radius: 4px;
display: flex;
.button-geocoder {
border: none;
padding: 0;
margin: 0;
text-align: center;
background-color: #fff;
color: rgb(39, 39, 39);
width: 30px;
height: 30px;
font: 700 18px Lucida Console,Monaco,monospace;
border-radius: 2px;
line-height: 1.15;
i {
margin: 0;
font-size: 0.9em;
}
}
.button-geocoder:hover {
cursor: pointer;
background-color: #ebebeb;
}
.expanded-geocoder {
max-width: 400px;
}
&&.isExpanded {
.button-geocoder {
height: 41px;
color: rgb(99, 99, 99);
border-radius: 2px 0 0 2px;
}
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// /* keep placeholder width when opening dropdown */
.multiselect {
min-width: 208px;
}
/* keep font-weight from overide of semantic classes */
.multiselect__placeholder, .multiselect__content, .multiselect__tags {
font-weight: initial !important;
}
/* keep placeholder eigth */
.multiselect .multiselect__placeholder {
margin-bottom: 9px !important;
padding-top: 1px;
}
/* keep placeholder height when opening dropdown without selection */
input.multiselect__input {
padding: 3px 0 0 0 !important;
}
/* keep placeholder height when opening dropdown with already a value selected */
.multiselect__tags .multiselect__single {
padding: 1px 0 0 0 !important;
margin-bottom: 9px;
}
.multiselect__tags {
border: 0 !important;
min-height: 41px !important;
}
.multiselect input {
line-height: 1em !important;
padding: 0 !important;
}
.multiselect__content-wrapper {
border: 2px solid rgba(0,0,0,.2);
}