Skip to content

Instantly share code, notes, and snippets.

@ovcharik
Last active August 29, 2015 14:01
Show Gist options
  • Save ovcharik/4602a0f54b086559a91d to your computer and use it in GitHub Desktop.
Save ovcharik/4602a0f54b086559a91d to your computer and use it in GitHub Desktop.
JQuery autocomplite from google autocomplite service with groups and additional custom sources.

JQuery autocomplite with google places service and groups

Виджет для jquery.ui, базирует на стандартном автокомплите.

Возможности

Автоматический поиск данных через Google Places, фильтрация и группировка результатов. Также есть возможность загрузки полной информации о выбранном месте.

Требования

Необходимо помимо jquery.ui подключить underscore и google maps with places service.

Использование

Свойства

  • sources - дополнительный источник данных
  • loadDetails - true или false, если значение истинно, то по выбору места будет загружена дополнительная информация о нем, по умолчанию в true
  • ignoreUngrouped - игнорирование данных, которые не вошли в не одну из групп, по умолчанию в true
  • ungroupLabel - метка для данных без группы
  • ungroupClass - дополнительный класс для элемента группы не сгруппированных данных
  • groups - массив описывающий группы на которые будут поделены данные, каждая группа описывается следующими полями:
    • label - Текст который будет выводится в группе
    • class - Добавочный класс
    • types - массив типов Google Places, либо типы пользовательских данных.

Свойства Google Autocomplite

bounds, location, radius, types.

Подробнее

События

  • select - тык
  • detailsReceived - срабатывает при получении полной информации о месте, для пользовательских данных просто возвращается, то что было передано, возвращаемые параметры: event, google places result, selected item
  • detailsFailed - при ошибке загрузки дополнительных данных, возвращаемые параметры: event, google places result, selected item

JQuery.ui.autocomplite

Так как виджет основан на нем доступны все свойства, методы и события базового автокомлита.

Пример использования

$( selector ).geocomplite({
  minLength: 2,
  autoFocus: true,
  
  types: ['establishment', 'geocode'],
  groups: [
    { label: "Области (Субъекты)",    class: "district_mod",      types: ["administrative_area_level_1"] },
    { label: "Города",                class: "city_mod",          types: ["locality"] },
    { label: "Районы города",         class: "district_mod",      types: ["sublocality"] },
    { label: "Улицы",                 class: "street_mod",        types: ["route"] },
    { label: "Метро",                 class: "subway_mod",        types: ["metro"] },
    { label: "Достопримечательности", class: "establishment_mod", types: ["establishment"] }
  ],
  
  source: function(request, response) {
    var stations = getMetroStations(request);
    response(stations);
  },
  
  detailsReceived: function(event, result, item) {
    if (result.metro) {
      addMetro(result);
    }
    else {
      addPlace(result);
    }
  }
});
if (!$) throw "JQuery required";
if (!_) throw "Underscore required";
if (!google || !google.maps || !google.maps.places) throw "Google map places required";
$.widget("custom.geocomplite", $.ui.autocomplete, {
_placesService: new google.maps.places.PlacesService(document.createElement("input")),
_autocompliteService: new google.maps.places.AutocompleteService(),
_listOfQueryOptions: ['bounds', 'location', 'radius', 'types'],
_okStatus: google.maps.places.PlacesServiceStatus.OK,
_create: function() {
this._superApply(arguments);
// load details hook
this._on(this.element, {
geocompliteselect: function(event, ui) {
var _this = this;
if (this.options.loadDetails) {
var item = ui.item;
if (item.reference) {
this._placesService.getDetails(item, function(response, status) {
if (status === _this._okStatus) {
_this._trigger("detailsReceived", null, [response, item]);
}
else {
_this._trigger("detailsFailed", null, [response, item]);
}
});
}
else {
_this._trigger("detailsReceived", null, [item, item]);
}
}
}
});
// change sources
this.additionalSource = this.source;
this.source = this._source;
},
_getQueryOptions: function() {
var result = {};
for (var i in this._listOfQueryOptions) {
var key = this._listOfQueryOptions[i];
if (this.options[key]) {
result[key] = this.options[key]
}
}
return result;
},
_procResults: function(results) {
var data = [];
var groups = this.options.groups;
for (var i in results) {
var add = false;
var result = results[i];
result.value = result.value || result.label || result.description;
result.label = result.label || result.value || result.description;
// grouping
for (var g in groups) {
var groupTypes = groups[g].types;
if (!groupTypes) {
continue;
}
if (!$.isArray(groupTypes)) {
groupTypes = [groupTypes];
}
for (var t in groupTypes) {
add = add || _.include(result.types, groupTypes[t]);
if (add) {
result.group = groups[g];
result.groupId = g;
break;
}
}
if (add) break;
}
if (add || !this.options.ignoreUngrouped) {
data.push(result);
}
}
return data;
},
_sortItems: function(items) {
return _.sortBy(items, function(item) { return item.groupId; });
},
_groupItems: function(items) {
return _.groupBy(items, function(item) { return item.groupId; });
},
_renderMenu: function(ul, items) {
var grouped = this._groupItems(items);
for (var key in grouped) {
var value = grouped[key];
var group = this.options.groups[key] || this._getUngroup();
ul.append( "<li class='ui-autocomplete-category " + group.class + "'>" + group.label + "</li>" );
for (var i in value) {
this._renderItemData(ul, value[i]);
}
}
},
_getUngroup: function() {
return {
class: this.options.ungroupClass || "",
label: this.options.ungroupLabel || ""
}
},
_geoSource: function(request, response) {
var _this = this;
var options = this._getQueryOptions();
options.input = request.term;
this._autocompliteService.getPredictions(options, function(results, status, info) {
if (status === _this._okStatus) {
response(results);
}
else {
response();
}
});
},
_source: function(request, response) {
var _this = this;
var data = [];
this._geoSource(request, function(result) {
if (result) data = data.concat(result);
if (_this.additionalSource) {
_this.additionalSource(request, function(result) {
if (result) data = data.concat(result);
data = _this._procResults(data);
response(data);
});
}
else {
data = _this._procResults(data);
response(data);
}
});
},
options: {
// data
source: null,
// flags
loadDetails: true,
ignoreUngrouped: true,
// query options
bounds: null,
location: null,
radius: null,
types: null,
// groups
groups: null,
ungroupLabel: null,
ungroupClass: null,
// events
detailsReceived: null,
detailsFailed: null
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment