| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- <template>
- <div>
- <v-autocomplete
- v-model="model"
- :loading="loading"
- :items="items"
- :search-input.sync="search"
- hide-no-data
- hide-details
- return-object
- auto-select-first
- clearable
- :label="$t('where') + ' ?'"
- outlined
- append-icon="mdi-crosshairs-gps"
- @change="$emit('change', $event ? $event.value : '')"
- @click:append="geolocalizeUser"
- />
- <v-snackbar :value="errorMsg !== ''">
- {{ errorMsg }}
- <template #action="{ attrs }">
- <v-btn text v-bind="attrs" @click="errorMsg=''">
- {{ $t('close') }}
- </v-btn>
- </template>
- </v-snackbar>
- </div>
- </template>
- <script lang="ts">
- import Vue from 'vue'
- /**
- * Address properties as returned by the https://geo.api.gouv.fr/adresse API
- */
- interface AddressProperties {
- label: string,
- score: number,
- housenumber: string,
- id: string,
- name: string,
- postcode: string,
- citycode: string,
- x: number,
- y: number,
- city: string,
- district: string,
- context: string,
- type: 'housenumber' | 'street' | 'locality' | 'municipality'
- importance: number,
- street: string
- }
- /**
- * Localized addresses as returned by the https://geo.api.gouv.fr/adresse API
- */
- interface Feature {
- type: 'Feature',
- geometry: { type: 'Point', coordinates: [ number, number ]},
- properties: AddressProperties
- }
- export default Vue.extend({
- props: {
- value: {
- type: String,
- required: false,
- default: ''
- },
- type: {
- type: String,
- required: false,
- default: 'housenumber',
- validator (value: string) {
- return ['housenumber', 'street', 'locality', 'municipality'].includes(value)
- }
- },
- limit: {
- type: Number,
- required: false,
- default: 5
- },
- autocomplete: {
- type: Boolean,
- required: false,
- default: true
- }
- },
- data () {
- return {
- model: null as Address | null,
- search: null,
- features: [] as Array<Feature>,
- loading: false,
- errorMsg: ''
- }
- },
- computed: {
- items (): Array<Address> {
- return this.features.map((f: Feature) => {
- return {
- text: f.properties.name + ' (' + f.properties.postcode + ')',
- value: { longitude: f.geometry.coordinates[0] as number, latitude: f.geometry.coordinates[1] as number },
- disabled: false
- }
- })
- }
- },
- watch: {
- search (val: string) {
- if (!val) {
- this.features = []
- return
- }
- this.loading = true
- // Lazily load input items
- const apiUrl = 'https://api-adresse.data.gouv.fr/search/' +
- `?type=${this.type}` +
- `&autocomplete=${this.autocomplete ? 1 : 0}` +
- `&limit=${this.limit}` +
- `&q=${val}`
- fetch(encodeURI(apiUrl))
- .then(res => res.json())
- .then(({ features }) => {
- this.features = features
- })
- .catch((err) => {
- // eslint-disable-next-line no-console
- console.error(err)
- })
- .finally(() => {
- this.loading = false
- })
- }
- },
- methods: {
- clear () {
- this.model = null
- this.search = null
- this.features = []
- this.loading = false
- this.errorMsg = ''
- },
- geolocalizeUser () {
- if (navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(
- (position: { coords: { longitude: number, latitude: number }}) => {
- this.model = {
- text: this.$t('my_position') as string,
- value: { longitude: position.coords.longitude, latitude: position.coords.latitude }
- }
- },
- () => {
- this.errorMsg = this.$t('geolocation_error') as string
- }
- )
- } else {
- this.errorMsg = this.$t('geolocation_not_supported') as string
- }
- }
- }
- })
- </script>
- <style>
- .v-input__control {
- height: 56px;
- }
- </style>
|