Яндекс.Карты → API Яндекс.Карт: геокодирование и автозаполнение результатов

Многие пользовались API Яндекс.Карт, я в том числе. Не буду заострять внимание на том, что такое геокодирование - это можно почитать тут. Цель этой статьи рассказать о том, как можно сделать поиск адресов на карте с автозаполнением результатов в строку поиска, так как API Яндекс.Карт не дает решения этой задачи. Для решения будем использовать JQuery 1.8.2 и JQuery UI 1.9.1 (потребуется виджет Autocomplete).

Поехали

Для начала создадим новую карту, как это сделать - подробно описано в документации API:

Карта

Добавим текстовое поле, которое будем использовать в качестве поисковой строки:

  1. <input id="Address" value="" />

Теперь создадим функцию, которая по мере ввода поисковой фразы будет выдавать результаты поиска в выпадающем списке, с возможностью автозаполнения:

  1. $(document).ready(function(){
  2. $("#Address").keyup(function(){
  3. //по мере ввода фразы, событие будет срабатывать всякий раз
  4. var search_query = $(this).val();
  5. //массив, в который будем записывать результаты поиска
  6. search_result = [];
  7. //делаем запрос к геокодеру
  8. $.getJSON('http://geocode-maps.yandex.ru/1.x/?format=json&geocode='+search_query, function(data) {
  9. //геокодер возвращает объект, который содержит в себе результаты поиска
  10. //для каждого результата возвращаются географические координаты и некоторая дополнительная информация
  11. //ответ геокодера легко посмотреть с помощью console.log();
  12. for(var i = 0; i < data.response.GeoObjectCollection.featureMember.length; i++) {
  13. //записываем в массив результаты, которые возвращает нам геокодер
  14. search_result.push({
  15. label: data.response.GeoObjectCollection.featureMember[i].GeoObject.description+' - '+data.response.GeoObjectCollection.featureMember[i].GeoObject.name,
  16. value:data.response.GeoObjectCollection.featureMember[i].GeoObject.description+' - '+data.response.GeoObjectCollection.featureMember[i].GeoObject.name,
  17. longlat:data.response.GeoObjectCollection.featureMember[i].GeoObject.Point.pos});
  18. }
  19. //подключаем к текстовому полю виджет autocomplete
  20. $("#Address").autocomplete({
  21. //в качестве источника результатов указываем массив search_result
  22. source: search_result,
  23. select: function(event, ui){
  24. //это событие срабатывает при выборе нужного результата
  25.  
  26. }
  27. });
  28. });
  29. });
  30. });

В 20-ой строке к текстовому полю подключается виджет autocomplete. Но есть одна проблема - сам виджет будет фильтровать результаты поиска, показывая на экран только те результаты, которые содержат полностью поисковую фразу. Например, если искать по фразе "Удмуртская 1", то геокодер по мимо прочих результатов вернет результаты вида "... Удмуртская улица, 1 ..." и так далее, но виджет исключит эти результаты поиска, так как они не содержат в себе исходную поисковую фразу - это не правильно и такой поиск будет работать не верно, смотрите демо 1 (По запросу "Удмуртская 1" результат будет пустым, хотя ответ геокодера не пустой). Чтобы решить эту проблему нужно копнуть исходный код самого виджета autocomplete

В виджете autocomplete за фильтрацию результатов поиска отвечают методы filter и escapeRegex:

  1. $.extend( $.ui.autocomplete, {
  2. escapeRegex: function( value ) {
  3. return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
  4. },
  5. filter: function(array, term) {
  6. var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
  7. return $.grep( array, function(value) {
  8. return matcher.test( value.label || value.value || value );
  9. });
  10. }
  11. });

Чтобы заставить autocomplete отображать все результаты поиска как есть, изменим метод filter, но, конечно, мы не будем изменять исходный код библиотеки, а переопределим этот метод, не трогая саму библиотеку. Ниже показан код метода filter, вынесенный за пределы исходной библиотеки, который теперь не фильтрует результаты поиска в соответствии с поисковой фразой, а отображает все результаты, которые возвращает геокодер:

  1. $(document).ready(function(){
  2. $("#Address").keyup(function(){
  3. ................
  4. });
  5.  
  6. $.ui.autocomplete.filter = function (array, term) {
  7. return $.grep(array, function (value) {
  8. return value.label || value.value || value;
  9. });
  10. };
  11. });

Окончательный вариант работы поиска по адресу с функцией автозаполнения - Демо 2

Комментарии

Спасибо огромное! Разъяснил все очень(!) понятно.

У вас в IE демо 2 работает ?

Заработало, если добавить в строку запроса &callback=?
т.е.
$.getJSON('http://geocode-maps.yandex.ru/1.x/?format=json&callback=?&geocode=' + searchQuery, function (data) {
итд

Да, спасибо, добавил и в демо.

Здравствуйте! Благодарю за пример! А не подскажите, пожалуйста, как сделать для нескольких полей?
Чтобы названия полей были массивом в таком виде:

  1. <input name=adress[0] value="">
  2. <input name=adress[1] value="">

и т.д.?

И можно ли как-то контролировать вывод выбранного адреса?
Например, если ищется ул. Тверская, то чтобы после выбора её из поля удалялось название страны?

С выводом в своём формате разобрался)

И с адресами разобрался)
Всё, вопросы снимаю.

Доброго времени суток!
Пытаюсь понять как можно изменить формат вывода результатов поиска.
К примеру в примере №2 результат является таким:
микрорайон Завод Измерительных Приборов, Краснодар, Россия - Зиповская улица, 8
, а на официальной странице Яндекс Карт при введении того же адреса результат такой:
Россия, Краснодар, микрорайон Завод Измерительных Приборов, Зиповская улица, 8
Что нужно изменить для того, что бы страна и город выводились в начале результата, как на странице Яндекс Карт?
И еще один вопрос, нигде не могу найти как можно удалить с карты метку от предыдущего поиска, или передвинуть ее?
Заранее спасибо!

Добрый день, обратите внимание на место, где заполняется массив search_result, можно посмотреть что за данные используются и вывести их в нужном формате. Метка добавляется в коде с помощью ymaps.Placemark. Можно доработать код и удалять метку при начале нового поиска или что-то в этом роде.

Хорошая статья и хорошая работа!
Спасибо1

Добавить комментарий