Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Geocoder refactoring using axios and AbortController objects. Fixes #400 #416

Merged
merged 4 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading