Skip to content

Instantly share code, notes, and snippets.

@Haroenv
Created November 27, 2019 10:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Haroenv/c73d1e3f5dd887d3e21751ec02c4b7d9 to your computer and use it in GitHub Desktop.
Save Haroenv/c73d1e3f5dd887d3e21751ec02c4b7d9 to your computer and use it in GitHub Desktop.
A Vue + Places.js widget
<template>
<!-- container for places.js -->
<div>
<div id="algolia-places" />
</div>
</template>
<script>
import { createWidgetMixin } from 'vue-instantsearch';
import places from 'places.js';
import { places_config, store } from '../store.js';
let placeName;
const connectPlaces = (
renderFn,
unmountFn
) => (/* widgetParams, if this would become reusable */) => {
return {
init() {
renderFn({ nearMe: undefined }, true);
},
render({ state }) {
renderFn({ nearMe: state.aroundLatLngViaIP === 'true' }, false);
},
dispose() {
unmountFn();
},
getWidgetState(uiState, { searchParameters }) {
return {
...uiState,
latlng: searchParameters.aroundLatLng,
nearme: searchParameters.aroundLatLngViaIP,
place: placeName,
};
},
getWidgetSearchParameters(searchParameters, { uiState }) {
placeName = uiState.place;
return searchParameters
.setQueryParameter('aroundLatLng', uiState.latlng)
.setQueryParameter('aroundLatLngViaIP', uiState.nearme);
},
};
};
export default {
mixins: [createWidgetMixin({ connector: connectPlaces })],
data() {
return {
instance: null,
};
},
mounted() {
// make sure Vue does not know about the input
// this way it can properly unmount
this.input = document.createElement('input');
this.input.placeholder = 'e.g. town, city, street';
if (placeName) {
setTimeout(() => {
this.instance.setVal(placeName);
}, 0);
}
this.$el.appendChild(this.input);
this.addNearMeListener();
this.instance = places({
appId: places_config.APP_ID,
apiKey: places_config.API_KEY,
container: this.input,
}).configure({
countries: ['GB', 'IE'],
});
this.onChange = e => {
placeName = e.suggestion.value;
this.instantSearchInstance.helper
.setQueryParameter(
'aroundLatLng',
e.suggestion.latlng.lat + ',' + e.suggestion.latlng.lng
)
.setQueryParameter('aroundLatLngViaIP', undefined);
this.instantSearchInstance.helper.search();
};
this.onClear = () => {
store.setPlacesDialogOpened(false);
placeName = null;
this.instantSearchInstance.helper
.setQueryParameter('aroundLatLng', undefined)
.setQueryParameter('aroundLatLngViaIP', undefined);
this.instantSearchInstance.helper.search();
};
this.onShown = () => {
store.setPlacesDialogOpened(true);
}
this.onClosed = () => {
store.setPlacesDialogOpened(false);
}
this.instance.on('change', this.onChange);
this.instance.on('clear', this.onClear);
this.instance.autocomplete.on('autocomplete:shown', this.onShown);
this.instance.autocomplete.on('autocomplete:closed', this.onClosed);
},
beforeDestroy() {
this.removeNearMeListener();
// if you had any "this.instance.on", also call "off" here
this.instance.off('change', this.onChange);
this.instance.off('clear', this.onClear);
this.instance.autocomplete.off('autocomplete:shown', this.onShown);
this.instance.autocomplete.off('autocomplete:closed', this.onClosed);
this.instance.destroy();
},
methods: {
addNearMeListener() {
this.onInputChange = () => {
if (this.state.nearMe && this.input.value !== 'Near Me') {
placeName = null;
this.instance.setVal('');
this.instantSearchInstance.helper
.setQueryParameter('aroundLatLng', undefined)
.setQueryParameter('aroundLatLngViaIP', undefined);
this.instantSearchInstance.helper.search();
this.removeNearMeListener();
}
};
this.input.addEventListener('input', this.onInputChange);
},
removeNearMeListener() {
if (this.onInputChange) {
this.input.removeEventListener('input', this.onInputChange);
this.onInputChange = null;
}
},
},
};
</script>
<style lang="scss" scoped>
/deep/ .ap-dropdown-menu.ap-with-places .ap-suggestion .ap-suggestion-icon {
background-size: 14px 21px;
background-repeat: no-repeat;
background-image: url(~@/assets/location-pin.png);
display: inline-block;
width: 14px;
height: 21px;
svg {
display: none;
}
}
/deep/ .algolia-places .ap-icon-pin {
display: none;
}
/deep/ .ap-input {
background-size: 18px 27px;
background-repeat: no-repeat;
background-image: url(~@/assets/location-pin.png);
background-position: 17px 11px;
padding: 15px 15px 15px 51px !important;
}
// mobile header
@media screen and (max-width: $tablet) {
/deep/ .ap-dropdown-menu.ap-with-places {
width: calc(100% + 44px);
top: 60px !important;
left: -22px !important;
}
/deep/ .algolia-places .ap-icon-clear {
position: absolute !important;
top: 15px;
right: 6px !important;
width: 21px;
height: 21px;
border: none;
padding: 0;
cursor: pointer;
svg {
width: 100%;
height: 100%;
fill: #fff;
@include theme-value(background-color, brand-color-one);
border-radius: 100%;
padding: 4px
}
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment