PDA

View Full Version : Custom Store/Proxy for search combo



pauldugas
11 Feb 2011, 2:50 PM
I'm looking for suggested approaches to building a custom Store/Proxy for use with a combo I'm using as a search field for a map panel. I've been digging through Google and the code looking at the various Ext.data components but I'm not sure where the right place to begin is.

I've got the combo setup with the trigger hidden. I want the user to start entering text and once enough characters are entered, fire off a call to Google's geocoding API, and have the first few results appear as options for the combobox. I pressing enter or perhaps a second trigger would center the map on the selected entry.

What the "right" approach here?

Condor
12 Feb 2011, 12:36 AM
The GeoCoding API supports JSONP protocol, so you should use a ScriptTagProxy and a JsonReader.

pauldugas
12 Feb 2011, 6:36 AM
Thanks Condor. That'll work for this. I'm curious though... If I were to want to use their google.maps.Geocoder class or some other 3rd-party API of some kind, how would one go about building the custom Ext.data.Store et all to wrap it?

Condor
12 Feb 2011, 7:29 AM
You could use a DirectProxy and write your own 'conversion' methods.

pauldugas
14 Feb 2011, 7:41 AM
I tried using JsonStore and ScriptTagProxy per Condor's suggestion but I'm missing something.



this.ds = new Ext.data.JsonStore({
proxy: new Ext.data.ScriptTagProxy({
url: 'http://maps.googleapis.com/maps/api/geocode/json'
}),
baseParams: { sensor: false },
idProperty: 'formatted_address',
successProperty: 'status',
root: 'results',
fields: [
{name: 'types'},
{name: 'formatted_address'},
{name: 'address_components'},
{name: 'geometry'}
]
});
combo = new Ext.form.ComboBox({
store: this.ds,
queryParam: 'address'
// ...
});


I'm getting an "Uncaught SyntaxError: Unexpected token :" error. The returned JSON response looks like so:


{ "status": "ZERO_RESULTS", "results": [ ] }

Isn't it supposed to have the callback call in there? Is JSONP messed up in their newest V3 API?

EDIT: The JSON is in response to an empty request so the empty "results" is expected. The URL requested was http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=&callback=stcCallback1001

pauldugas
14 Feb 2011, 8:33 AM
Been doing some more reading and it appears JSONP support has been pulled from the V3 version of Google's GeoCoder API. The documentation directs us to their google.maps.Geocoder class instead. So, I'm looking more into your suggestion that I look into using DirectProxy. I've been poking around in the code for a couple hours and I'm not sure where to begin. What "conversion" routines are you referring to?

Sorry for being a pest.

pauldugas
15 Feb 2011, 6:38 AM
So, more digging. Here's what I've come up with. Seems to be working...


Ext.ux.GeocoderProxy = function() {
var api = {};
api[Ext.data.Api.actions.read] = true;
Ext.ux.GeocoderProxy.superclass.constructor.call(this, { api: api });
this.geocoder = new google.maps.Geocoder();
}
Ext.extend(Ext.ux.GeocoderProxy, Ext.data.DataProxy, {
doRequest: function(action, rs, params, reader, callback, scope, arg) {
this.geocoder.geocode(params, this.doResponse.createDelegate(this,
[reader, callback, scope, arg], true));
},
doResponse: function(results, status, reader, callback, scope, arg) {
var success = (status == google.maps.GeocoderStatus.OK);
for (var i=0, len=results.length; i<len; ++i) { results[i].id = i; }
callback.call(scope, reader.readRecords({
success: success,
results: results
}), arg, true);
}
});
Ext.ux.GeocoderStore = Ext.extend(Ext.data.Store, {
constructor: function(config) {
var c = Ext.apply({}, { /* foo:bar */ }, config);
Ext.ux.GeocoderStore.superclass.constructor.call(this, Ext.apply(c, {
proxy: new Ext.ux.GeocoderProxy(),
reader: new Ext.data.ArrayReader({
successProperty: 'success',
root: 'results'
}, [
{name: 'id', mapping: 'id' },
{name: 'address', mapping: 'formatted_address' },
{name: 'components', mapping: 'address_components' },
{name: 'types', mapping: 'types' },
{name: 'geometry', mapping: 'geometry' }
])
}));
}
});