Autocomplete com plugin JS e JSON
Bom dia amigos programadores, espero que estejam todos bem.
Preciso de uma ajuda urgente para criar um sistema de autocomplete para um projeto que estou fazendo.
Funciona assim: é um sistema de busca de passagens aéreas, no estilo decolar.com. Mas um pouco mais simples. O usuário começa a digitar o local que quer de origem, aí aparece o sistema de autocomplete. Esse sistema de autocomplete está sendo feito com o plugin jQuery typeahead (https://twitter.github.io/typeahead.js/). E os locais estão sendo puxados de um json (que vou por logo abaixo). Quando o usuário clica no local que ele escolher, existe dois campos do tipo hidden, um para o slug do local e outro para o ID do local, todos puxados do json. Assim, quando o usuário clica, automaticamente o formulário preenche os dois campos abaixo. O mesmo acontece quando o usuário preenche o o local de volta - funciona exatamente do mesmo jeito. O formulário passa as informações via GET.
Segue os códigos:
<form method="GET" id="homeSearch" data-base-action="/es/buscar/city_1876/city_1794/" novalidate="novalidate">
<ul class="lp-holder-fields">
<li class="lp-column full">
<label class="lb-form" for="originPlace">Origen:</label>
<input id=" " name="searchBox[originPlace]" placeholder="Seleccione su origen" type="text" tabindex="1" autocomplete="off" class="input_lup searchInput" value="">
<input id="originPlaceId" type="hidden" value="">
<input id="originPlaceSlug" type="hidden" value="">
</li>
<li class="lp-column full">
<label class="lb-form" for="destinationPlace">Destino:</label>
<input id="destinationPlace" name="searchBox[destinationPlace]" placeholder="Seleccione su destino" type="text" tabindex="2" class="input_lup searchInput" autocomplete="off" value="">
<input id="destinationPlaceId" type="hidden" value="">
<input id="destinationPlaceSlug" type="hidden" value="">
</li>
<li class="lp-column full">
<label class="lb-form" for="departureDate">Salida:</label>
<input type="text" placeholder="Fecha de ida" id="departureDate" name="searchBox[departureDate]" class="datepicker input_date searchInput fixIE_searchDepartureHome" tabindex="3" autocomplete="off" value="">
<input type="hidden" id="departureDateHdn" name="ida" value="">
</li>
<li class="lp-column full">
<label class="lb-form" for="returnDate">Regreso <small>(opcional)</small>:</label>
<input type="text" placeholder="Opcional" id="returnDate" name="searchBox[returnDate]" class="datepicker input_date searchInput" tabindex="4" autocomplete="off" value="">
<input type="hidden" id="returnDateHdn" name="volta" value="">
</li>
<li>
<button tabindex="5" id="btn-search" class="search_tickets"><span class="i_search"></span><span>Buscar Boletos</span></button>
</li>
</ul>
</form>
Esse é o formulário (o projeto é em espanhol). Eu tenho o input "originPlace", que é onde o usuário preenche o local de origem e terá o autocomplete. Logo abaixo tem os dois inputs hidden que puxarão o slug e o ID desse local que o usuário escolher. O mesmo vale para o input "destinationPlace". Os outros inputs são para escolher data e, no momento, está tudo certo.
Segue o código javaScript junto com o JSON.
$(function() {
try {
$.datepicker.setDefaults($.datepicker.regional['es']);
} catch (e) {}
var originsSlugs = [];
var $originPlace = $('#originPlace');
var $destinationPlace = $('#destinationPlace');
var placeListByName = [{
"name": "Terminal,\x20Abasolo,\x20GTO",
"slug": "abasolo\x2Dgto",
"id": 5000,
"isGroup": ""
}, {
"name": "Aeropuerto,\x20Guadalajara,\x20JAL",
"slug": "aeropuerto\x2Dguadalajara\x2Djal",
"id": 5001,
"isGroup": ""
}, {
"name": "Aeropuerto\x20terminal\x201,\x20Ciudad\x20de\x20M\u00E9xico,\x20DF",
"slug": "aeropuerto\x2Dmexico\x2Dterminal\x2D1\x2Dciudad\x2Dde\x2Dmexico\x2Ddf",
"id": 5003,
"isGroup": ""
}, {
"name": "Aeropuerto\x20terminal\x202,\x20Ciudad\x20de\x20M\u00E9xico,\x20DF",
"slug": "aeropuerto\x2Dmexico\x2Dterminal\x2D2\x2Dciudad\x2Dde\x2Dmexico\x2Ddf",
"id": 5004,
"isGroup": ""
}, {
"name": "Terminal,\x20Aguascalientes,\x20AGS",
"slug": "aguascalientes\x2Dags",
"id": 5005,
"isGroup": ""
}, {
"name": "Terminal,\x20Ahuacatl\u00E1n\x20de\x20Guadalupe,\x20QRO",
"slug": "ahuacatlan\x2Dde\x2Dguadalupe\x2Dqro",
"id": 5006,
"isGroup": ""
},];
var hashTable = {};
var orderedPlaceList = {};
for (var x = 0; x < placeListByName.length; x++) {
orderedPlaceList[x] = placeListByName[x].name;
hashTable[placeListByName[x].name] = placeListByName[x];
}
var originPlaceNames = _.uniq(_.flatten(_.values(orderedPlaceList)))
try {
var originPlaceSlug = $.trim($('#originPlaceSlug').val()),
destinationPlaceSlug = $.trim($('#destinationPlaceSlug').val());
if (originPlaceSlug) {
var originPlaceSlugEntity = _.findWhere(placeListByName, {
slug: originPlaceSlug
});
if (!originPlaceSlugEntity) {
$('#originPlace').val('');
$('#originPlaceId').val('');
$('#originPlaceSlug').val('');
}
}
if (destinationPlaceSlug) {
var destinationPlaceSlugEntity = _.findWhere(placeListByName, {
slug: destinationPlaceSlug
});
if (!destinationPlaceSlugEntity) {
$('#destinationPlace').val('');
$('#destinationPlaceId').val('');
$('#destinationPlaceSlug').val('');
}
}
} catch (e) {}
var typeaheadSorter = function(items) {
var originalPlaces = _.map(items, function(item) {
return hashTable[item];
});
var orderedItemsByIsGroup = _.sortBy(originalPlaces, function(originPlace) {
return originPlace.isGroup === '' ? 1 : 0;
});
return _.pluck(orderedItemsByIsGroup, 'name');
}
$originPlace.typeahead({
source: originPlaceNames,
matcher: function(item) {
var cleanItem = removeDiacritics(item).toLowerCase();
var cleanQuery = removeDiacritics(this.query).toLowerCase();
var result = (cleanItem.indexOf(cleanQuery) === 0 || cleanItem.search(cleanQuery) >= 0);
return result;
},
updater: function(item) {
var city = null;
if ($.trim(item) !== '') {
city = _.findWhere(placeListByName, {
name: item
});
}
if (city) {
$('#originPlaceId').val(city.id);
$('#originPlaceSlug').val(city.slug);
} else {
$('#originPlaceId').val(0);
$('#originPlaceSlug').val('');
$(this).val('');
}
return item;
},
sorter: typeaheadSorter
});
$destinationPlace.typeahead({
source: originPlaceNames,
matcher: function(item) {
var cleanItem = removeDiacritics(item).toLowerCase();
var cleanQuery = removeDiacritics(this.query).toLowerCase();
var result = (cleanItem.indexOf(cleanQuery) === 0 || cleanItem.search(cleanQuery) >= 0);
return result;
},
updater: function(item) {
var city = null;
if ($.trim(item) !== '') {
city = _.findWhere(placeListByName, {
name: item
});
}
if (city) {
$('#destinationPlaceId').val(city.id);
$('#destinationPlaceSlug').val(city.slug);
} else {
$('#destinationPlaceId').val(0);
$('#destinationPlaceSlug').val('');
$(this).val('');
}
return item;
},
sorter: typeaheadSorter,
header: "teste"
});
var getDestinations = function(city) {
if (window.isAutoCompleteEnabled) {
var adjacencylist = $.ajax({
url: "/es/adjacencylistplace",
method: "GET",
data: {
"parameter": "departure",
"placeId": city.id
},
dataType: "json"
});
adjacencylist.done(destinationList);
}
};
var originPlaceHandler = function() {
var $this = $(this);
var resultOriginPlaceName = $this.val();
if (!resultOriginPlaceName) {
return false;
}
var city = null;
if ($.trim(resultOriginPlaceName) !== '') {
city = _.findWhere(placeListByName, {
name: resultOriginPlaceName
});
}
if (city) {
if (city.isGroup == "1") {
$('#isGroup').val(0);
}
$('#originPlaceId').val(city.id);
$('#originPlaceSlug').val(city.slug);
getDestinations(city);
} else {
$('#originPlaceId').val(0);
$('#originPlaceSlug').val('');
$(this).val('');
}
};
var destinationList = function(ids) {
var routesList;
routesList = routesToPlacesList(ids).sort();
$destinationPlace.typeahead().data('typeahead').source = routesList;
};
var routesToPlacesList = function(routesList) {
var placesList, placeListId;
placeListId = _.indexBy(placeListByName, 'id');
placesList = _.map(routesList, function(route) {
if (typeof placeListId[route.arrival] !== 'undefined') {
return placeListId[route.arrival].name;
}
});
originsSlugs = _.map(routesList, function(route) {
return {
"departure_slug": route.departure_slug,
"id": route.arrival
};
});
return placesList;
};
$originPlace.bind('blur', originPlaceHandler);
$destinationPlace.bind('blur', function() {
var cityName = $(this).val(),
city = null;
if (cityName !== '') {
city = _.findWhere(placeListByName, {
name: cityName
});
}
if (city) {
if (window.isAutoCompleteEnabled) {
var slugGroup = _.findWhere(originsSlugs, {
id: city.id
});
if ($('#originPlaceSlug').val() != slugGroup.departure_slug) {
$('#isGroup').val(1);
}
$('#originPlaceSlug').val(slugGroup.departure_slug);
}
if (city.isGroup == "1") {
$('#isGroup').val(0);
}
$('#destinationPlaceId').val(city.id);
$('#destinationPlaceSlug').val(city.slug);
} else {
$('#destinationPlaceId').val(0);
$('#destinationPlaceSlug').val('');
$(this).val('');
}
});
});
Logo no começo temos o json com as informações dos locais etc. Coloquei apenas alguns de exemplo para não estender tanto o código. Na parte de baixo temos o código que faz funcionar a passagens dos dados para o input hidden quando o usuário seleciona o local e também o código do autocomplete.
No momento está funcionando perfeitamente - o problema é que eu preciso fazer uma alteração nesse código que não estou conseguindo. Eu preciso separar a exibição do autocomplete em dois - em Cidades (Ciudades) e Aeroportos (Aeropuertos). Lembrando que estou usando o plugin typeahead. Basicamente eu preciso fazer o mesmo que está nesse link (https://twitter.github.io/typeahead.js/examples/) lá na parte de "Multiple Datasets". O problema é que não consigo de jeito nenhum fazer isso funcionar. Já tentei vários exemplos e já estou desesperado. Alguém pode me ajudar, por favor?
Agradeço de todo coração!
Discussão (0)
Carregando comentários...