Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

avallon-azevedo

Autocomplete com plugin JS e JSON

Recommended Posts

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!

Compartilhar este post


Link para o post
Compartilhar em outros sites

  • Conteúdo Similar

    • Por juniormatrix
      Olá
       
      Achei esse script aqui no fórum mesmo:
       
      $.validator.addMethod( "customEmail", function (value, element) { return this.optional(element) || /^[\w-\.]+@fulano\.com\.br$/i.test(value); }, "Por favor, insira um e-mail válido com o domínio @fulano.com.br" ); $("#formulario").validate({ ignore: ".ignore", rules: { empresa: { required: true }, nome: { required: true }, contato: { required: true }, celular: { required: true }, email: { required: true, email: true, customEmail: true }, }, }); Testei e funcionou perfeitamente, mas gostaria que liberasse mais e-mails válidos, ao invés de apenas um.

      Tem como fazer? 
       
      Se alguém puder ajudar, fico muito grato.
    • Por clovis.sardinha
      Tenho uma consulta de autocomplete no bd que funciona no servidor local e não roda no servidor da web. 
      Ao enviar a consulta no servidor local  aparece no console :Fetch terminou o carregamento: GET ".../Cidade?cidade=sao%20paulo". A pesquisa é feita normalmente.
      Quando mando a mesma pesquisa para o servidor web(locaweb) aparece no console: Fetch terminou o carregamento: GET "..../Cidade?cidade=sao%2520paul".
      O número 25 aparece só no servidor web. Pelo que pesquisei 25 significa %, ou seja, está duplicando o caractere %. 
      Não consegui utilizar nenhuma função para evitar que isto ocorra. Alguém sabe se há alguma configuração no servidor web que possa ser alterada para evitar essa duplicação?
       
    • Por clovis.sardinha
      Estou em um impasse pois sei pouco de javascript. Estou fazendo um autocomplete com CI4 e Javascript.
      Consigo gerar, através do controllers/model do CI4 um arquivo em json, mas não consigo retorná-lo para o javascript para poder mostrar as opções para consulta. 
      O console.log mostra que estou obtendo o  json() { [native code] }.
      Segue os dois arquivos para ver se alguém me ajuda.
      //arquivo cidade.js async function carregar_cidade(valor) { if (valor.length >= 3) { //console.log("Pesquisar:" + valor); const dados = fetch('Testes/?cidade='+valor, { method: "get", headers: { "Content-Type": "application/json", "X-Requested-With": "XMLHttpRequest" } }); const resposta = (await dados).json; console.log(resposta); var html = "<ul class='list-group position-fixed'>"; html += "<li class='list-group-item'>" + resposta['cid_nome'] + "</li>"; html += "</ul>"; } } <?php //arquivo Testes.php namespace App\Controllers; use App\Models\CidadeModel; /** NÃO MANDAR PARA O SERVIDOR - APENAS TESTES DE FUNÇÕES E OUTROS ELEMENTOS DO CI4 */ class Testes extends BaseController{ protected $tbCidades; public function __construct(){ $this->tbCidades = new CidadeModel(); } public function index(){ $request = \Config\Services::request(); $client = \Config\Services::curlrequest(); $cidades=[]; if($get=$request->getGet()){ $cities=$get['cidade']; $cidadeFiltrada=$this->tbCidades->getCidByName($cities); $cidades= json_encode($cidadeFiltrada); //dd($cidades); } echo view('Testes/testes'); } public function salvar(){ $request = \Config\Services::request(); if($post=$request->getPost()){ dd($post); } } } <!doctype html> <html lang="pt-br"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Bootstrap CSS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous"> <title>Autocomplete</title> </head> <body> <div class="container"> <h1 class="mt-4 mb-4">Formulário</h1> <form class="row g-3"> <div class="col-12"> <label for="cidade" class="form-label">Cidade</label> <input type="text" name="cidade" class="form-control" id="cidade" placeholder="Pesquisar cidade" onkeyup="carregar_cidade(this.value)"> </div> <span ></span> </form> </div> <!-- Optional JavaScript; choose one of the two! --> <!-- Option 1: Bootstrap Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script> <script src="assets/js/cidade.js"></script> </body> </html>
    • Por Alessandro Bodão
      Salve galerinha, passando pra mostrar pra vocês o novo projeto de marca que a Jatobá Estúdio desenvolveu, espero que gostem.   https://www.behance.net/gallery/166555627/Fernanda-Pinheiro-Nutricionista-Esportiva
    • Por rogerblower
      Boas pessoal, estou precisando de um calendário para agenda com crud para agendamento, mas teria que ser free.
      Obrogado.
×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.