Skip to content

Commit 60f8e54

Browse files
committed
Mapbox autocompletion
1 parent b98397a commit 60f8e54

File tree

7 files changed

+100
-10
lines changed

7 files changed

+100
-10
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,18 @@ mymap:
199199
- country
200200
```
201201

202+
202203
#### 5.4. `draggable`
203204

204205
If set to `true`, the marker will be repositionable in case search result isn't precise enough. After being moved, only the new `lat` and `lng` will be stored. Default is `true`.
205206

206-
#### 5.5. `liststyle`
207+
208+
#### 5.5. `autocomplete`
209+
210+
If set to `true`, **when Mapbox is used for geocoding**, you will be presented up to 5 suggestions while typing your request. Default is `true`.
211+
212+
213+
#### 5.6. `liststyle`
207214

208215
![liststyle](https://user-images.githubusercontent.com/14079751/48487819-9cf91580-e81f-11e8-8e20-eba57f122261.jpg)
209216

@@ -216,7 +223,7 @@ mymap:
216223
```
217224

218225

219-
#### 5.6. `marker`
226+
#### 5.7. `marker`
220227

221228
The color of the marker used, either `dark` or `light` (in case you are using `mapbox.dark` as your tile-layer). Default is `dark`.
222229

@@ -241,6 +248,7 @@ return array(
241248
'sylvainjule.locator.zoom.max' => 18,
242249
'sylvainjule.locator.display' => array('lat','lon','number','address','postcode','city','country'),
243250
'sylvainjule.locator.draggable' => true,
251+
'sylvainjule.locator.autocomplete' => true,
244252
'sylvainjule.locator.liststyle' => 'columns',
245253
'sylvainjule.locator.marker' => 'dark',
246254
);

config.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
'geocoding' => 'nominatim',
99
'display' => array('lat','lon','number','address','postcode','city','country'),
1010
'draggable' => true,
11+
'autocomplete' => true,
1112
'zoom.min' => 2,
1213
'zoom.default' => 12,
1314
'zoom.max' => 18,

index.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/fields.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
'draggable' => function($draggable = null) {
2121
return $draggable ?? option('sylvainjule.locator.draggable');
2222
},
23+
'autocomplete' => function($autocomplete = null) {
24+
return $autocomplete ?? option('sylvainjule.locator.autocomplete');
25+
},
2326
'zoom' => function($zoom = []) {
2427
return array(
2528
'min' => $zoom['min'] ?? option('sylvainjule.locator.zoom.min'),

src/assets/css/styles.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
----------------------------*/
1414

1515
.k-locator-input {
16+
position: relative;
1617
display: flex;
1718
align-items: center;
19+
overflow: visible;
20+
z-index: 3;
1821
.k-text-input {
1922
@include text-truncate;
2023
}
@@ -45,6 +48,20 @@
4548
}
4649
}
4750
}
51+
.k-dropdown-content {
52+
max-width: 100%;
53+
overflow: hidden;
54+
.k-location-type {
55+
color: #999;
56+
margin-left: .25rem;
57+
&:before {
58+
content: " (";
59+
}
60+
&:after {
61+
content: ")";
62+
}
63+
}
64+
}
4865
}
4966

5067

src/field/Locator.vue

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
<template>
22
<k-field :input="_uid" v-bind="$props" class="k-locator-field">
33
<div class="k-input k-locator-input" data-theme="field">
4-
<input ref="input" v-model="location" class="k-text-input" :placeholder="$t('locator.placeholder')">
4+
<input ref="input" v-model="location" class="k-text-input" :placeholder="$t('locator.placeholder')" @input="onLocationInput">
55
<button :class="[{disabled: !location.length}]" @click="getCoordinates"><svg><use xlink:href="#icon-locator-locate" /></svg> {{ $t('locator.locate') }}</button>
6+
<k-dropdown-content v-if="autocomplete" ref="dropdown">
7+
<k-dropdown-item v-for="(option, index) in dropdownOptions"
8+
:key="index"
9+
@click="select(option)"
10+
@keydown.native.enter.prevent="select(option)"
11+
@keydown.native.space.prevent="select(option)">
12+
<span v-html="option.name" />
13+
<span class="k-location-type" v-html="option.type" />
14+
</k-dropdown-item>
15+
</k-dropdown-content>
616
</div>
717
<k-dialog ref="dialog" @close="error = ''">
818
<k-text>{{ error }}</k-text>
@@ -40,6 +50,8 @@ export default {
4050
tileLayer: null,
4151
location: '',
4252
error: '',
53+
limit: 1,
54+
dropdownOptions: [],
4355
}
4456
},
4557
props: {
@@ -52,6 +64,7 @@ export default {
5264
geocoding: String,
5365
liststyle: String,
5466
draggable: Boolean,
67+
autocomplete: Boolean,
5568
5669
// general options
5770
label: String,
@@ -118,10 +131,10 @@ export default {
118131
return 'https://nominatim.openstreetmap.org/search?format=jsonv2&limit=1&addressdetails=1&q=' + this.location
119132
}
120133
else if(this.geocoding == 'mapbox') {
121-
return 'https://api.mapbox.com/geocoding/v5/mapbox.places/'+ this.location +'.json?types=address,country,postcode,place,locality&limit=1&access_token=' + this.mapbox.token
134+
return 'https://api.mapbox.com/geocoding/v5/mapbox.places/'+ this.location +'.json?types=address,country,postcode,place,locality&limit='+ this.limit +'&access_token=' + this.mapbox.token
122135
}
123136
else return ''
124-
}
137+
},
125138
},
126139
watch: {
127140
value() {
@@ -132,6 +145,47 @@ export default {
132145
this.initMap()
133146
},
134147
methods: {
148+
onLocationInput() {
149+
if(!this.autocomplete) return false
150+
151+
if(this.geocoding && this.location.length) {
152+
if(this.geocoding != 'mapbox') return false
153+
154+
this.limit = 5
155+
fetch(this.searchQuery)
156+
.then(response => response.json())
157+
.then(response => {
158+
// if places are found
159+
if(response.features.length) {
160+
// keep the relevant ones
161+
let suggestions = response.features.filter(el => el.relevance == 1)
162+
// make them the dropdown options
163+
this.dropdownOptions = suggestions.map(el => {
164+
return {
165+
name: el.place_name,
166+
type: this.capitalize(el.place_type[0]),
167+
}
168+
})
169+
this.$refs.dropdown.open()
170+
}
171+
else {
172+
this.$refs.dropdown.close()
173+
}
174+
})
175+
.catch(error => {
176+
this.error = this.$t('locator.error')
177+
this.$refs.dialog.open()
178+
this.$refs.dropdown.close()
179+
})
180+
}
181+
else {
182+
this.$refs.dropdown.close()
183+
}
184+
},
185+
select(option) {
186+
this.location = option.name
187+
this.getCoordinates()
188+
},
135189
translatedTitle(key) {
136190
key = key.replace('lon', 'longitude')
137191
key = key.replace('lat', 'latitude')
@@ -185,8 +239,13 @@ export default {
185239
})
186240
},
187241
getCoordinates(e) {
188-
e.preventDefault()
189-
e.stopPropagation()
242+
if(e) {
243+
e.preventDefault()
244+
e.stopPropagation()
245+
}
246+
247+
if(this.$refs.dropdown) this.$refs.dropdown.close()
248+
this.limit = 1
190249
191250
if(this.geocoding && this.location.length) {
192251
fetch(this.searchQuery)
@@ -199,7 +258,6 @@ export default {
199258
else if(this.geocoding == 'mapbox') {
200259
this.setMapboxResponse(response)
201260
}
202-
203261
this.location = ''
204262
}
205263
else {
@@ -240,6 +298,9 @@ export default {
240298
'address': response.text || '',
241299
}
242300
},
301+
capitalize(str) {
302+
return str.charAt(0).toUpperCase() + str.slice(1);
303+
}
243304
},
244305
}
245306
</script>

0 commit comments

Comments
 (0)