我们有一个我们想要提供输入的地址字段。它位于登录后面,但如果我们需要,我们可以变得狡猾,并将这一页公开以获得许可合规性。
Google Maps API已被锁定。我们曾经使用它的“反向地理编码”部分来执行地址的部分地址搜索/预先输入 - 例如,如果用户键入:
1600 Penn
我可以点击该服务并获得一些建议,例如:
1600 Washington Avenue,Washington,DC
我遇到过其他几个部分地址搜索但他们每个人都有问题。
谷歌:每天仅需7500个请求,每年最低10000美元 - 荒谬雅虎:今年关闭
Bing:要求页面公开/不在登录后面。这对我们来说并不是一件难事,但对页面的工作方式进行重新设计将是一项挑战。
Mapquest OpenStreetMap API:搜索确切的字符串而不是前导字符串 - 因此它返回Penn Station而不是1600 Pennsylvania Ave.
Mapquest OpenStreetMap数据:我们可以下载所有这些并实现我们自己的数据,但CPU和数据要求可能暂时不会太多。
我们支付使用费用很好,我们只是寻求一个比亚马逊的$ 0.01 / 10000要求更接近Google的解决方案。
答案 0 :(得分:1)
更新:我的原始答案,完整地在下面,在SmartyStreets提供address autocomplete之前提供,使用LiveAddress API订阅免费提供。
这很简单,真的。 USPS已批准某些供应商提供地址验证/标准化服务。我为一家这样的公司SmartyStreets工作,根据我的经验,你想要做的事情可能比你想到的具有REST端点的好API更容易。查看LiveAddress API。
提交街道地址,至少提供城市/州或邮政编码,或两者兼而有之,您将获得建议结果列表。
但是,请注意,Google地图等非CASS提供商确实会解决近似问题,而不会解决地址验证问题。谷歌和其他人做出了“最好的猜测”,谷歌和他们都是专家。如果您想要实际的现有地址,请确保找到能够实现此目的的服务。我将补充说LiveAddress现在是免费的,并提供比USPS API更好的性能。
答案 1 :(得分:0)
Google发布了Google Places Autocomplete,解决了这个问题。
在页面底部将其放入:
<script defer async src="//maps.googleapis.com/maps/api/js?libraries=places&key=(key)&sensor=false&callback=googPlacesInit"></script>
(key)
是您的API密钥。
我们设置了我们的代码,因此您可以标记某些字段以处理预先输入并通过该类型输入填写,例如:
<input name=Address placeholder=Address />
<input name=Zip placeholder=Zip />
等
然后您初始化它(通常在Google Places API加载之前,因为它将导致异步):
GoogleAddress.init('#billing input', '#shipping input');
或者其他什么。在这种情况下,它将地址预先输入绑定到#billing标记和#shipping标记中具有name = Address的任何输入,并且当地址时它将填充City,State,Zip等标记内的相关字段被选中。
设置课程:
var GoogleAddress = {
AddressFields: [],
//ZipFields: [], // Not in use and the support code is commented out, for now
OnSelect: [],
/**
* @param {String} field Pass as many arguments as you like, each a selector to a set of inputs that should use Google
* Address Typeahead via the Google Places API.
*
* Mark the inputs with name=Address, name=City, name=State, name=Zip, name=Country
* All fields are optional; you can for example leave Country out and everything else will still work.
*
* The Address field will be used as the typeahead field. When an address is picked, the 5 fields will be filled in.
*/
init: function (field) {
var args = $.makeArray(arguments);
GoogleAddress.AddressFields = $.map(args, function (selector) {
return $(selector);
});
}
};
上面的脚本片段将异步调用到名为googPlacesInit
的函数中,因此其他所有内容都被该名称包含在函数中:
function googPlacesInit() {
var fields = GoogleAddress.AddressFields;
if (
// If Google Places fails to load, we need to skip running these or the whole script file will fail
typeof (google) == 'undefined' ||
// If there's no input there's no typeahead so don't bother initializing
fields.length == 0 || fields[0].length == 0
)
return;
设置自动完成事件,并处理我们始终使用多个地址字段的事实,但Google希望将整个地址转储到单个输入中。肯定有办法防止这种情况发生,但我还没有找到它。
$.each(fields, function (i, inputs) {
var jqInput = inputs.filter('[name=Address]');
var addressLookup = new google.maps.places.Autocomplete(jqInput[0], {
types: ['address']
});
google.maps.event.addListener(addressLookup, 'place_changed', function () {
var place = addressLookup.getPlace();
// Sometimes getPlace() freaks out and fails - if so do nothing but blank out everything after comma here.
if (!place || !place.address_components) {
setTimeout(function () {
jqInput.val(/^([^,]+),/.exec(jqInput.val())[1]);
}, 1);
return;
}
var a = parsePlacesResult(place);
// HACK! Not sure how to tell Google Places not to set the typeahead field's value, so, we just wait it out
// then overwrite it
setTimeout(function () {
jqInput.val(a.address);
}, 1);
// For the rest, assign by lookup
inputs.each(function (i, input) {
var val = getAddressPart(input, a);
if (val)
input.value = val;
});
onGoogPlacesSelected();
});
// Deal with Places API blur replacing value we set with theirs
var removeGoogBlur = function () {
var googBlur = jqInput.data('googBlur');
if (googBlur) {
jqInput.off('blur', googBlur).removeData('googBlur');
}
};
removeGoogBlur();
var googBlur = jqInput.blur(function () {
removeGoogBlur();
var val = this.value;
var _this = this;
setTimeout(function () {
_this.value = val;
}, 1);
});
jqInput.data('googBlur', googBlur);
});
// Global goog address selected event handling
function onGoogPlacesSelected() {
$.each(GoogleAddress.OnSelect, function (i, fn) {
fn();
});
}
将结果解析为规范的街道1,街道2,城市,州/省,邮政编码并非易事。 Google会根据您所在的世界的不同来区分这些地区,并且作为警告,例如非洲有些地方可以满足您对地址的期望。您可以将世界上的地址分为3类:
美国完全相同 - 整个美国和几个使用类似寻址系统的国家
正式地址 - 英国,澳大利亚,中国,基本上是发达国家 - 但他们的地址部分是标签的方式存在相当大的差异
没有正式地址 - 在未开发的地区,没有街道名称,更不用说街道号码,有时甚至不是城镇/城市名称,当然也没有拉链。在这些位置,您真正想要的是GPS位置,此代码无法处理。
此代码仅尝试处理前两种情况。
function parsePlacesResult(place) {
var a = place.address_components;
var p = {};
var d = {};
for (var i = 0; i < a.length; i++) {
var ai = a[i];
switch (ai.types[0]) {
case 'street_number':
p.num = ai.long_name;
break;
case 'route':
p.rd = ai.long_name;
break;
case 'locality':
case 'sublocality_level_1':
case 'sublocality':
d.city = ai.long_name;
break;
case 'administrative_area_level_1':
d.state = ai.short_name;
break;
case 'country':
d.country = ai.short_name;
break;
case 'postal_code':
d.zip = ai.long_name;
}
}
var addr = [];
if (p.num)
addr.push(p.num);
if (p.rd)
addr.push(p.rd);
d.address = addr.join(' ');
return d;
}
/**
* @param input An Input tag, the DOM element not a jQuery object
* @paran a A Google Places Address object, with props like .city, .state, .country...
*/
var getAddressPart = function(input, a) {
switch(input.name) {
case 'City': return a.city;
case 'State': return a.state;
case 'Zip': return a.zip;
case 'Country': return a.country;
}
return null;
}
ArcGis / ESRI具有有限的预先解决方案功能,但只有在输入相当多的情况下才会返回有限的结果。这里有一个演示:
http://www.esri.com/services/disaster-response/wildlandfire/latest-news-map.html
例如,您可以键入1600 Pennsylvania Ave,希望在您输入#34; 1600 Penn&#34;时获得白宫,但必须达到&#34; 1600宾夕法尼亚大街,华盛顿特区&# 34;在它回复该地址之前。尽管如此,它可以为用户节省时间。