2019-07-30 10:35:29 +02:00
|
|
|
<template>
|
2020-07-31 17:52:26 +02:00
|
|
|
<b-autocomplete
|
|
|
|
:data="addressData"
|
|
|
|
v-model="queryText"
|
|
|
|
:placeholder="$t('e.g. 10 Rue Jangot')"
|
|
|
|
field="fullName"
|
|
|
|
:loading="isFetching"
|
|
|
|
@typing="fetchAsyncData"
|
|
|
|
icon="map-marker"
|
|
|
|
expanded
|
|
|
|
@select="updateSelected"
|
|
|
|
>
|
|
|
|
<template slot-scope="{ option }">
|
|
|
|
<b-icon :icon="option.poiInfos.poiIcon.icon" />
|
|
|
|
<b>{{ option.poiInfos.name }}</b
|
|
|
|
><br />
|
|
|
|
<small>{{ option.poiInfos.alternativeName }}</small>
|
|
|
|
</template>
|
|
|
|
<template slot="empty">
|
|
|
|
<span v-if="isFetching">{{ $t("Searching…") }}</span>
|
|
|
|
<div v-else-if="queryText.length >= 3" class="is-enabled">
|
|
|
|
<span>{{ $t('No results for "{queryText}"') }}</span>
|
|
|
|
<span>{{
|
|
|
|
$t("You can try another search term or drag and drop the marker on the map", {
|
|
|
|
queryText,
|
|
|
|
})
|
|
|
|
}}</span>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</b-autocomplete>
|
2019-07-30 10:35:29 +02:00
|
|
|
</template>
|
|
|
|
<script lang="ts">
|
2020-02-18 08:57:00 +01:00
|
|
|
import { Component, Prop, Vue, Watch } from "vue-property-decorator";
|
|
|
|
import { LatLng } from "leaflet";
|
|
|
|
import { debounce } from "lodash";
|
|
|
|
import { Address, IAddress } from "../../types/address.model";
|
|
|
|
import { ADDRESS, REVERSE_GEOCODE } from "../../graphql/address";
|
|
|
|
import { CONFIG } from "../../graphql/config";
|
|
|
|
import { IConfig } from "../../types/config.model";
|
2019-11-08 19:37:14 +01:00
|
|
|
|
2019-08-22 15:57:44 +02:00
|
|
|
@Component({
|
2019-11-20 13:49:57 +01:00
|
|
|
apollo: {
|
|
|
|
config: CONFIG,
|
|
|
|
},
|
2019-08-22 15:57:44 +02:00
|
|
|
})
|
2019-07-30 10:35:29 +02:00
|
|
|
export default class AddressAutoComplete extends Vue {
|
2019-11-08 19:37:14 +01:00
|
|
|
@Prop({ required: true }) value!: IAddress;
|
2019-07-30 10:35:29 +02:00
|
|
|
|
2019-11-20 13:49:57 +01:00
|
|
|
addressData: IAddress[] = [];
|
2020-02-18 08:57:00 +01:00
|
|
|
|
2019-11-20 13:49:57 +01:00
|
|
|
selected: IAddress = new Address();
|
2020-02-18 08:57:00 +01:00
|
|
|
|
|
|
|
isFetching = false;
|
|
|
|
|
|
|
|
queryText: string = (this.value && new Address(this.value).fullName) || "";
|
|
|
|
|
2019-11-20 13:49:57 +01:00
|
|
|
config!: IConfig;
|
2019-11-08 19:37:14 +01:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
fetchAsyncData!: Function;
|
|
|
|
|
|
|
|
// We put this in data because of issues like
|
|
|
|
// https://github.com/vuejs/vue-class-component/issues/263
|
2019-11-20 13:49:57 +01:00
|
|
|
data() {
|
|
|
|
return {
|
2019-12-20 11:39:30 +01:00
|
|
|
fetchAsyncData: debounce(this.asyncData, 200),
|
2019-11-20 13:49:57 +01:00
|
|
|
};
|
2019-11-08 19:37:14 +01:00
|
|
|
}
|
2019-07-30 10:35:29 +02:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
async asyncData(query: string) {
|
2019-11-08 19:37:14 +01:00
|
|
|
if (!query.length) {
|
2019-11-20 13:49:57 +01:00
|
|
|
this.addressData = [];
|
2019-11-08 19:37:14 +01:00
|
|
|
this.selected = new Address();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.length < 3) {
|
2019-11-20 13:49:57 +01:00
|
|
|
this.addressData = [];
|
2019-07-30 10:35:29 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-11-20 13:49:57 +01:00
|
|
|
|
2019-07-30 10:35:29 +02:00
|
|
|
this.isFetching = true;
|
|
|
|
const result = await this.$apollo.query({
|
|
|
|
query: ADDRESS,
|
2020-02-18 08:57:00 +01:00
|
|
|
fetchPolicy: "network-only",
|
2019-11-08 19:37:14 +01:00
|
|
|
variables: {
|
|
|
|
query,
|
|
|
|
locale: this.$i18n.locale,
|
|
|
|
},
|
2019-07-30 10:35:29 +02:00
|
|
|
});
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
this.addressData = result.data.searchAddress.map((address: IAddress) => new Address(address));
|
2019-08-22 15:57:44 +02:00
|
|
|
this.isFetching = false;
|
2019-07-30 10:35:29 +02:00
|
|
|
}
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@Watch("config")
|
|
|
|
watchConfig(config: IConfig) {
|
2019-11-20 13:49:57 +01:00
|
|
|
if (!config.geocoding.autocomplete) {
|
2020-02-18 08:57:00 +01:00
|
|
|
// If autocomplete is disabled, we put a larger debounce value
|
|
|
|
// so that we don't request with incomplete address
|
2019-11-20 13:49:57 +01:00
|
|
|
this.fetchAsyncData = debounce(this.asyncData, 2000);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
@Watch("value")
|
2019-11-20 13:49:57 +01:00
|
|
|
updateEditing() {
|
2019-12-03 11:29:51 +01:00
|
|
|
if (!(this.value && this.value.id)) return;
|
2019-11-20 13:49:57 +01:00
|
|
|
this.selected = this.value;
|
|
|
|
const address = new Address(this.selected);
|
|
|
|
this.queryText = `${address.poiInfos.name} ${address.poiInfos.alternativeName}`;
|
|
|
|
}
|
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
updateSelected(option: IAddress) {
|
2019-11-08 19:37:14 +01:00
|
|
|
if (option == null) return;
|
|
|
|
this.selected = option;
|
2020-02-18 08:57:00 +01:00
|
|
|
this.$emit("input", this.selected);
|
2019-07-30 10:35:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
2019-08-22 15:57:44 +02:00
|
|
|
<style lang="scss">
|
2020-02-18 08:57:00 +01:00
|
|
|
.address-autocomplete {
|
|
|
|
margin-bottom: 0.75rem;
|
|
|
|
}
|
2019-12-20 13:04:34 +01:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
.autocomplete {
|
|
|
|
.dropdown-menu {
|
|
|
|
z-index: 2000;
|
|
|
|
}
|
2019-11-08 19:37:14 +01:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
.dropdown-item.is-disabled {
|
|
|
|
opacity: 1 !important;
|
|
|
|
cursor: auto;
|
|
|
|
}
|
|
|
|
}
|
2019-11-08 19:37:14 +01:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
.read-only {
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
2019-11-08 19:37:14 +01:00
|
|
|
|
2020-02-18 08:57:00 +01:00
|
|
|
.map {
|
|
|
|
height: 400px;
|
|
|
|
width: 100%;
|
|
|
|
}
|
2019-08-22 15:57:44 +02:00
|
|
|
</style>
|