2011-11-08 94 views
2

我們有一個地址字段,我們希望提供typeahead。它位於登錄後面,儘管如果我們需要我們可以狡猾並且公開一個頁面來實現許可合規。部分地址搜索/ Typeahead

Google Maps API被鎖定。我們習慣用它的「反向地理」部分的地址進行部分地址搜索/預輸入 - 因此,例如,如果用戶鍵入:

總統一家

我可以打服務,並取回一些建議,如:

賓夕法尼亞大道1600號,華盛頓特區

還有其他幾個部分地址搜索在那裏我碰到過,但他們每個人都有問題。

谷歌:$ 10000 /年最低僅售7500請求/日 - 可笑

雅虎:關機今年

兵:需要的頁面是公開/不落後登錄。這對我們來說並不難,但這將是一個具有挑戰性的重新設計網頁的工作方式。

Mapquest OpenStreetMap API:搜索確切的字符串,而不是一個主要的字符串 - 因此它返回賓州車站而不是賓夕法尼亞大道1600號。 Mapquest OpenStreetMap數據:我們可以下載所有這些並實現我們自己的,但CPU和數據要求可能會太多,以至於暫時沒有辦法。

我們支付使用費很好,我們只是尋求一個解決方案,接近亞馬遜的0.01美元/ 10000的請求比谷歌的。

回答

0

更新

谷歌已經發布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 /> 

然後初始化它(谷歌之前的地方API已經載典型,因爲那將土地異步)有:

GoogleAddress.init('#billing input', '#shipping input'); 

或什麼的。在這種情況下,它將地址typeahead綁定到#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(); 
    }); 
} 

解析結果到規範化street1,STREET2,城市,州/省,郵政編碼/郵遞區號是不平凡的。谷歌根據你所處的世界的不同而區分了這些地點,並且作爲一個警告,例如在非洲,有些地方不符合你對地址的看法。你可以打破世界地址可分爲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賓夕法尼亞大道希望通過你輸入「總統一家」,但必須讓儘可能「1600賓夕法尼亞大道的時間去白宮,華盛頓特區「,然後再回復該地址。但是,它可以爲用戶節省時間帶來一點好處。

0

如何自己做這不是一個選項? IMO在地址,街道,城市等地區進行部分搜索或打字並不困難。

+0

客戶端的服務器已經處於高負載狀態。更大的產品(如Google)對這些查詢採用邊緣緩存響應,我們的最佳情況會比較慢。它似乎是應該有答案的那些大問題之一。 –

1

UPDATE:我原來的答案,下面完好,被賦予SmartyStreets有一個address autocomplete產品,該產品是免費使用LiveAddress API訂閱之前。


這很簡單,真的。 USPS已經批准了某些供應商進行地址驗證/標準化服務。我爲一家這樣的公司工作,根據我的經驗,您嘗試執行的操作可能比您認爲的具有REST端點的良好API更容易。查看LiveAddress API。

提交一個街道地址和至少一個城市/州,或郵政編碼,或兩者,你會得到一個建議結果的列表。

但是,請注意,非CASS提供程序(如Google地圖)確實解決了近似問題,而不是地址驗證問題。 Google和其他人都做出了「最佳猜測」,這是Google和他們的專家。如果你想要實際存在的地址,請確保你找到一個服務來做到這一點。我將補充一點,LiveAddress現在是免費的,並且比USPS API提供更好的性能。

+0

如果您要求用戶在驗證之前輸入完整地址,這似乎可以,但如果您要實現真正的自動完成(例如公司首頁上的自動完成),則成本可能會失控。免費套餐的使用限制使其對演示產品以外的任何其他功能無用。 – ach

+0

@ach實際上,SmartyStreets的自動完成服務完全免費,並且可以在您看到的首頁上提前輸入:http://smartystreets.com/kb/faq/autocomplete-endpoint – Matt