Skip to content

Commit

Permalink
Merge pull request #416 from sronveaux/geocoder-with-axios
Browse files Browse the repository at this point in the history
Geocoder refactoring using axios and AbortController objects. Fixes #400
  • Loading branch information
sronveaux authored Sep 24, 2024
2 parents bcf6a5e + 66f312b commit 7564b80
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 253 deletions.
55 changes: 55 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"@vue/cli-service": "~5.0.8",
"@vue/eslint-config-standard": "^8.0.1",
"@vue/test-utils": "^1.1.3",
"axios-mock-adapter": "^2.0.0",
"babel-plugin-istanbul": "^6.1.1",
"chai": "^4.3.10",
"copy-dir": "^1.2.0",
Expand Down
39 changes: 28 additions & 11 deletions src/components/geocoder/Geocoder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { GeocoderController } from './GeocoderController';
import { applyTransform } from 'ol/extent';
import { getTransform, fromLonLat } from 'ol/proj';
import ViewAnimationUtil from '../../util/ViewAnimation';
import axios from 'axios';
export default {
name: 'wgu-geocoder-input',
Expand All @@ -61,7 +62,7 @@ export default {
},
data () {
return {
results: [],
results: null,
lastQueryStr: '',
noFilter: true,
search: null,
Expand Down Expand Up @@ -98,19 +99,25 @@ export default {
},
// Query by string - should return list of selection items (adresses) for ComboBox
querySelections (queryStr) {
if (this.timeout) {
clearTimeout(this.timeout);
}
this.timeout = setTimeout(() => {
// Let Geocoder Provider do the query
// items (item.text fields) will be shown in combobox dropdown suggestions
this.trace(`geocoderController.query: ${queryStr}`);
this.geocoderController.query(queryStr)
.then(results => this.onQueryResults(results))
.catch(err => this.onQueryError(err))
.catch(err => {
if (!axios.isCancel(err)) {
this.onQueryError(err);
}
});
this.timeout = null;
}, this.queryDelay);
},
onQueryResults (results) {
// Handle query results from GeocoderController
this.timeout && clearTimeout(this.timeout);
this.timeout = null;
this.results = null;
if (!results || results.length === 0) {
Expand All @@ -130,9 +137,9 @@ export default {
watch: {
// Input string value changed
search (queryStr) {
if (this.timeout || this.selecting) {
// Query or selection in progress
this.trace('query or selection in progress...');
if (this.selecting) {
// Selection in progress
this.trace('selection in progress...');
return;
}
if (!queryStr || queryStr.length === 0) {
Expand All @@ -146,8 +153,10 @@ export default {
queryStr = queryStr.trim();
// Only query if minimal number chars typed and querystring has changed
queryStr.length >= this.minChars && queryStr !== this.lastQueryStr && this.querySelections(queryStr);
this.lastQueryStr = queryStr;
if (queryStr.length >= this.minChars && queryStr !== this.lastQueryStr) {
this.querySelections(queryStr);
this.lastQueryStr = queryStr;
}
},
// User has selected entry from suggested items
selected (item) {
Expand All @@ -160,7 +169,6 @@ export default {
// Position Map on result
const result = item.value;
const mapProjection = this.map.getView().getProjection();
const coords = fromLonLat([result.lon, result.lat], mapProjection);
// Prefer zooming to bounding box if present in result
if (Object.prototype.hasOwnProperty.call(result, 'boundingbox')) {
Expand All @@ -170,14 +178,23 @@ export default {
ViewAnimationUtil.to(this.map.getView(), extent);
} else {
// No bbox in result: center on lon/lat from result and zoom in
const coords = fromLonLat([result.lon, result.lat], mapProjection);
ViewAnimationUtil.to(this.map.getView(), coords);
}
this.selecting = false;
}
},
mounted () {
// Setup GeocoderController to which we delegate Provider and query-handling
this.geocoderController = new GeocoderController(this.provider, this.providerOptions, this);
this.geocoderController = new GeocoderController(this.provider, this.providerOptions);
},
destroyed () {
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
}
this.geocoderController.destroy();
}
}
</script>
45 changes: 21 additions & 24 deletions src/components/geocoder/GeocoderController.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import { OpenStreetMap } from './providers/osm';
import { Photon } from './providers/photon';
import { OpenCage } from './providers/opencage';
import { json } from './helpers/ajax';
import axios from 'axios';

// Geocoder Provider types
export const PROVIDERS = {
Expand All @@ -41,10 +41,10 @@ export class GeocoderController {
* @constructor
* @param {String} providerName name of Provider.
* @param {Object} options config options for Provider
* @param {Object} parent callback parent
*/
constructor (providerName, options, parent) {
constructor (providerName, options) {
this.options = options;
this.abortController = null;

// Must have Provider class defined for name
if (!Object.prototype.hasOwnProperty.call(PROVIDERS, providerName)) {
Expand All @@ -53,10 +53,21 @@ export class GeocoderController {
}
// Create Provider from name via Factory Method
this.provider = new PROVIDERS[providerName]();
this.parent = parent;
}

destroy () {
if (this.abortController) {
this.abortController.abort();
this.abortController = null;
}
}

async query (q) {
if (this.abortController) {
this.abortController.abort();
}
this.abortController = new AbortController();

const parameters = this.provider.getParameters({
query: q,
key: this.options.key,
Expand All @@ -65,28 +76,14 @@ export class GeocoderController {
limit: this.options.limit
});

const ajax = {
const request = {
method: 'GET',
url: parameters.url,
data: parameters.params
};

// Optional XHR with JSONP (Provider-specific)
if (parameters.callbackName) {
ajax.jsonp = true;
ajax.callbackName = parameters.callbackName;
params: parameters.params,
signal: this.abortController?.signal
}

const response = await json(ajax);
return this.provider.handleResponse(response)

// // Do the query via Ajax XHR, returning JSON. Async callback via Promise.
// json(ajax)
// .then(response => {
// // Call back parent with data formatted by Provider
// this.parent.onQueryResult(this.provider.handleResponse(response));
// })
// .catch(err => {
// this.parent.onQueryResult(undefined, err);
// });
const response = await axios(request);
return this.provider.handleResponse(response.data)
}
}
96 changes: 0 additions & 96 deletions src/components/geocoder/helpers/ajax.js

This file was deleted.

Loading

0 comments on commit 7564b80

Please sign in to comment.