twitter bootstrap typeahead ajax exemplo

280

Estou tentando encontrar um exemplo de trabalho do elemento de digitação de inicialização do twitter que fará uma chamada ajax para preencher sua lista suspensa.

Eu tenho um exemplo de preenchimento automático de jquery de trabalho existente que define o URL do ajax e como processar a resposta

<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
    var options = { minChars:3, max:20 };
    $("#runnerquery").autocomplete('./index/runnerfilter/format/html',options).result(
            function(event, data, formatted)
                {
                    window.location = "./runner/index/id/"+data[1];
                }
            );
       ..

O que preciso alterar para convertê-lo no exemplo do typeahead?

<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {
    var options = { source:'/index/runnerfilter/format/html', items:5 };
    $("#runnerquery").typeahead(options).result(
            function(event, data, formatted)
                {
                    window.location = "./runner/index/id/"+data[1];
                }
            );
       ..

Vou aguardar a solução do problema ' Adicionar suporte a fontes remotas para digitação antecipada '.

emeraldjava
fonte
Para ser mais específico, estou me perguntando como as opções de preenchimento automático e a função de manipulação de resultados são mapeadas para as opções do textahead? Existe um conjunto de funções definidas de manipulação de resultados de alerta de texto que podem ser substituídas ou são o método nomeado herdado da API jquery subjacente.
emeraldjava
1
Você poderia marcar a resposta de Stijn Van Bael como a correta agora? A resposta de Bogert funciona apenas para versões desatualizadas do Bootstrap.
Giles Roberts

Respostas:

302

Edit: typeahead não está mais incluído no Bootstrap 3. Confira:

Desde o Bootstrap 2.1.0 até a 2.3.2, você pode fazer o seguinte:

$('.typeahead').typeahead({
    source: function (query, process) {
        return $.get('/typeahead', { query: query }, function (data) {
            return process(data.options);
        });
    }
});

Para consumir dados JSON como este:

{
    "options": [
        "Option 1",
        "Option 2",
        "Option 3",
        "Option 4",
        "Option 5"
    ]
}

Observe que os dados JSON devem ser do tipo MIME correto (application / json) para que o jQuery o reconheça como JSON.

Stijn Van Bael
fonte
3
Como na bifurcação Typeahead, os dados devem ser uma matriz JSON de cadeias e o tipo de conteúdo deve ser application / json.
Stijn Van Bael
9
2.1 pode usar json que não é apenas uma matriz de strings? Eu preciso assim um valor para o usuário e usar um ID para fazer um processamento adicional. Isso é possível sem pegar um garfo personalizado?
Anton
2
@Stijin Existem exemplos de como essa função anônima seria usada aqui, para processar um ID para uma opção exibida? Obrigado!
Acyra
1
Gostaria de salientar que o uso desse método resulta em um AJAX chamado para cada pressionamento de tecla na entrada. Se o servidor está retornando dados essencialmente estáticos (ou seja, não está realmente fazendo nada com a consulta), isso pode ser um desperdício.
Dologan
2
por que usar em getvez de getJSON? Parece mais apropriado.
Greg0ire 21/05
119

Você pode usar o garfo BS Typeahead que suporta chamadas ajax. Então você será capaz de escrever:

$('.typeahead').typeahead({
    source: function (typeahead, query) {
        return $.get('/typeahead', { query: query }, function (data) {
            return typeahead.process(data);
        });
    }
});
Bogert
fonte
1
O "palpite inteligente" do jQuery para o tipo de retorno dos dados POST não estava funcionando quando retornei, por exemplo ["aardvark", "apple"],. Eu tive que definir explicitamente o dataTypeparâmetro na $.postchamada. Veja jQuery.post () .
Rusty Fausak /
1
@rfausak Como alternativa, defina o Content-typecabeçalho paraapplication/json
Rusty Fausak
23
Estou recebendo Uncaught TypeError: Não é possível chamar o método 'toLowerCase' de indefinido
Krishnaprasad Varma
No link que você enviou, nem estou conseguindo sourceexecutar a função.
James
8
Boa resposta! Em vez disso, usaria uma solicitação GET, apenas para atender aos padrões REST.
Mauro
72

A partir do Bootstrap 2.1.0:

HTML:

<input type='text' class='ajax-typeahead' data-link='your-json-link' />

Javascript:

$('.ajax-typeahead').typeahead({
    source: function(query, process) {
        return $.ajax({
            url: $(this)[0].$element[0].dataset.link,
            type: 'get',
            data: {query: query},
            dataType: 'json',
            success: function(json) {
                return typeof json.options == 'undefined' ? false : process(json.options);
            }
        });
    }
});

Agora você pode criar um código unificado, colocando os links "json-request" no seu código HTML.

Thantifaxath
fonte
11
Mas eu mudaria para usar $(this)[0].$element.data('link').
Andrew Ellis
outhis.$element.data('link')
Richard87 21/11
51

Todas as respostas se referem ao cabeçalho inicial do BootStrap 2, que não está mais presente no BootStrap 3.

Para qualquer pessoa direcionada aqui procurando um exemplo de AJAX usando o novo typeahead.js do Twitter pós-Bootstrap , aqui está um exemplo de trabalho. A sintaxe é um pouco diferente:

$('#mytextquery').typeahead({
  hint: true,
  highlight: true,
  minLength: 1
},
{
  limit: 12,
  async: true,
  source: function (query, processSync, processAsync) {
    processSync(['This suggestion appears immediately', 'This one too']);
    return $.ajax({
      url: "/ajax/myfilter.php", 
      type: 'GET',
      data: {query: query},
      dataType: 'json',
      success: function (json) {
        // in this example, json is simply an array of strings
        return processAsync(json);
      }
    });
  }
});

Este exemplo usa sugestões síncronas (a chamada para processSync ) e assíncronas; portanto, algumas opções são exibidas imediatamente e outras são adicionadas. Você pode apenas usar um ou outro.

Existem muitos eventos vinculáveis ​​e algumas opções muito poderosas, incluindo o trabalho com objetos em vez de seqüências de caracteres. Nesse caso, você usaria sua própria função de exibição personalizada para renderizar seus itens como texto.

Jonathan Lidbeck
fonte
1
Obrigado. Mais uma pergunta: com processAsync, estou recebendo "TypeError: suggestions.slice não é uma função". Como seria também o JSON retornado? Aqui está o meu melhor palpite: {: sugestões => ["Coisa 1", "Coisa 2", "Coisa 3"]}}
user1515295 26/11/2015
1
Certifique-se de retornar uma sequência JSON válida. Sua função sugestão AJAX deve retornar um array de strings, por exemplo ["Thing 1","Thing 2"], ou com uma função de exibição personalizada, uma matriz de objetos de acordo com as suas necessidades, por exemplo[{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}]
Jonathan Lidbeck
Eu voltar [{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}], agora eu quero mostrar duas colunas em suspenso typeahead com ID e rótulo. Como eu posso fazer isso?
Vishal 26/02
2
MEU DEUS!!! Eu estava pesquisando nos últimos 3 dias, ninguém mencionou isso. Eu estava testando com a função de sincronização até agora. VALEU CARA!!
Gilson PJ
Obrigado ! Funciona muito bem com o bootstrap 4.3 e o jquery 3.4. Porém, as opções listadas não são destacadas quando o mouse passa sobre ele. Eu pensei que deveria fazer parte da própria digitação.
Binita Bharati 10/10/19
25

Aumentei o plug-in Bootstrap original, com recursos de ajax. Muito fácil de usar:

$("#ajax-typeahead").typeahead({
     ajax: "/path/to/source"
});

Aqui está o repositório do github: Ajax-Typeahead

Paul Warelis
fonte
Eu olhei para o código de Gudbergur; francamente, eu gostei mais deste. É um pouco mais amigável e oferece mais funcionalidades. Bom trabalho Paul! A única coisa que eu sugiro é que, no seu README, lembre o usuário de que ele precisa analisar os dados JSON em JS para que seu código possa usá-lo corretamente. Eu assumi que você estava analisando para mim, o que me deixou um pouco confuso. Caso contrário, muito bom, obrigado! :)
Bane
3
Seu servidor retorna uma sequência em vez de um objeto JSON. $ .ajax () do jQuery é usado para fazer a chamada e cuida da análise.
Paul Warelis
1
absolutamente correto, obrigado pela captura! :) Este plugin funciona muito bem.
Bane 14/05
Olá, como deve ser o lado do servidor JSON? Eu estou recebendo Uncaught TypeError: Cannot read property 'length' of undefined . Estou usando json_encode($array)e enviando cabeçalhos corretos ( 'Content-Type: application/json; charset=utf-8'). Versão jqueryjQuery v1.9.1
Kyslik
5

Fiz algumas modificações no jquery-ui.min.js:

//Line 319 ORIG:
this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(...
// NEW:
this.menu=d("<ul></ul>").addClass("ui-autocomplete").addClass("typeahead").addClass("dropdown-menu").appendTo(d(...

// Line 328 ORIG:
this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr...
// NEW:this.element.attr....

// Line 329 ORIG:
this.active=a.eq(0).children("a")
this.active.children("a")
// NEW:
this.active=a.eq(0).addClass("active").children("a")
this.active.removeClass("active").children("a")`

e adicione o seguinte css

.dropdown-menu {
    max-width: 920px;
}
.ui-menu-item {
    cursor: pointer;        
}

Funciona perfeito.

bmoers
fonte
qual versão do jquery ui min você está usando?
Emeraldjava
Se você precisar disso para o jQuery 1.7.1 e o jQuery UI 1.8.16, criei um GIST com base na correção acima, que mostra onde alterar o arquivo da interface do usuário do jQuery. gist.github.com/1884819 - as linhas são comentadas com // modificado
Richard Hollis
Esta é uma pergunta / resposta bastante antiga, mas eu só quero dizer que é sempre uma má prática alterar o código de componentes de terceiros. Você precisará revisar todas as alterações sempre que atualizá-las. Nesse caso específico, os widgets jQuery podem ser herdados, o que é uma maneira muito mais segura de personalizá-los. Então, basicamente, crie seu próprio widget, herda do principal (o preenchimento automático neste caso) e libere sua imaginação! :)
AlexCode
3

Eu estou usando esse método

$('.typeahead').typeahead({
    hint: true,
    highlight: true,
    minLength: 1
},
    {
    name: 'options',
    displayKey: 'value',
    source: function (query, process) {
        return $.get('/weather/searchCity/?q=%QUERY', { query: query }, function (data) {
            var matches = [];
            $.each(data, function(i, str) {
                matches.push({ value: str });
            });
            return process(matches);

        },'json');
    }
});
Krava
fonte
Seria bom se você pudesse adicionar alguma explicação à sua resposta. Por exemplo, qual é a diferença da sua solução em comparação com as soluções apresentadas nas respostas já existentes?
Honk
2

Pode-se fazer chamadas usando o Bootstrap. A versão atual não apresenta nenhum problema de atualização da fonte. Problema ao atualizar a fonte de dados do tipo bootstrap com resposta posterior , ou seja, a fonte do bootstrap depois de atualizada pode ser modificada novamente.

Consulte abaixo um exemplo:

jQuery('#help').typeahead({
    source : function(query, process) {
        jQuery.ajax({
            url : "urltobefetched",
            type : 'GET',
            data : {
                "query" : query
            },
            dataType : 'json',
            success : function(json) {
                process(json);
            }
        });
    },
    minLength : 1,
});
neoeahit
fonte
2

Para aqueles que procuram uma versão com café da resposta aceita:

$(".typeahead").typeahead source: (query, process) ->
  $.get "/typeahead",
    query: query
  , (data) ->
    process data.options
Hendrik
fonte
2

Eu passei por este post e tudo não queria funcionar corretamente e, eventualmente, reuni os bits com algumas respostas, então eu tenho uma demonstração 100% funcional e a colo aqui para referência - cole-a em um arquivo php e verifique se as inclusões estão incluídas O lugar certo.

<?php if (isset($_GET['typeahead'])){
    die(json_encode(array('options' => array('like','spike','dike','ikelalcdass'))));
}
?>
<link href="bootstrap.css" rel="stylesheet">
<input type="text" class='typeahead'>
<script src="jquery-1.10.2.js"></script>
<script src="bootstrap.min.js"></script>
<script>
$('.typeahead').typeahead({
    source: function (query, process) {
        return $.get('index.php?typeahead', { query: query }, function (data) {
            return process(JSON.parse(data).options);
        });
    }
});
</script>
l0ft13
fonte
2

Tente isso se o seu serviço não estiver retornando o cabeçalho correto do aplicativo / tipo de conteúdo json:

$('.typeahead').typeahead({
    source: function (query, process) {
        return $.get('/typeahead', { query: query }, function (data) {
            var json = JSON.parse(data); // string to json
            return process(json.options);
        });
    }
});
Andres
fonte
1

UPDATE: modifiquei meu código usando este fork

também, em vez de usar $ .each, mudei para $ .map, como sugerido por Tomislav Markovski

$('#manufacturer').typeahead({
    source: function(typeahead, query){
        $.ajax({
            url: window.location.origin+"/bows/get_manufacturers.json",
            type: "POST",
            data: "",
            dataType: "JSON",
            async: false,
            success: function(results){
                var manufacturers = new Array;
                $.map(results.data.manufacturers, function(data, item){
                    var group;
                    group = {
                        manufacturer_id: data.Manufacturer.id,
                        manufacturer: data.Manufacturer.manufacturer
                    };
                    manufacturers.push(group);
                });
                typeahead.process(manufacturers);
            }
        });
    },
    property: 'name',
    items:11,
    onselect: function (obj) {

    }
});

No entanto, estou encontrando alguns problemas obtendo

TypeError não detectado: não é possível chamar o método 'toLowerCase' de undefined

como você pode ver em um post mais recente, estou tentando descobrir aqui

espero que esta atualização seja de alguma ajuda para você ...

mmoscosa
fonte
Não relacionado ao OP: em Array.mapvez disso, eu usaria $.eache substituiria o conteúdo de toda a sua successfunção de retorno de chamada porvar manufacturers = results.data.manufacturers.map(function (item) { return { id: item.Manufacturer.id, manufacturer: item.Manufacturer.manufacturer } });
Tomislav Markovski
obrigado @TomislavMarkovski Modifiquei meu código como você sugere.
precisa saber é
0

Não tenho um exemplo prático para você nem uma solução muito limpa, mas deixe-me contar o que encontrei.

Se você olhar para o código javascript para TypeAhead, ele será assim:

items = $.grep(this.source, function (item) {
    if (that.matcher(item)) return item
  })

Este código usa o método jQuery "grep" para corresponder a um elemento na matriz de origem. Eu não vi nenhum lugar que você pudesse conectar em uma chamada AJAX, portanto não há uma solução "limpa" para isso.

No entanto, uma maneira um tanto hacky que você pode fazer isso é tirar proveito da maneira como o método grep funciona no jQuery. O primeiro argumento para grep é a matriz de origem e o segundo argumento é uma função usada para corresponder à matriz de origem (observe que o Bootstrap chama o "correspondente" que você forneceu ao inicializá-lo). O que você pode fazer é definir a origem para uma matriz fictícia de um elemento e definir o correspondente como uma função com uma chamada AJAX. Dessa forma, ele executará a chamada AJAX apenas uma vez (já que sua matriz de origem possui apenas um elemento).

Essa solução não é apenas hacky, mas sofrerá com problemas de desempenho, pois o código TypeAhead foi projetado para fazer uma pesquisa a cada pressionamento de tecla (as chamadas AJAX devem realmente acontecer apenas a cada pressionamento de tecla ou após um certo tempo ocioso). Meu conselho é experimentá-lo, mas use uma biblioteca de preenchimento automático diferente ou use-a apenas para situações que não sejam do AJAX se você tiver algum problema.

Aamer Abbas
fonte
0

ao usar o ajax, tente em $.getJSON()vez de $.get()se tiver problemas com a exibição correta dos resultados.

No meu caso, obtive apenas o primeiro caractere de cada resultado quando usei $.get(), embora usei json_encode()no lado do servidor.

larsbo
fonte
0

eu uso $().one() para resolver isso; Quando a página é carregada, envio o ajax para o servidor e aguardo a conclusão. Depois passe o resultado para a função. $().one()é importante. Porque force typehead.js a anexar à entrada uma vez. desculpe por escrever mal.

(($) => {
    
    var substringMatcher = function(strs) {
        return function findMatches(q, cb) {
          var matches, substringRegex;
          // an array that will be populated with substring matches
          matches = [];
      
          // regex used to determine if a string contains the substring `q`
          substrRegex = new RegExp(q, 'i');
      
          // iterate through the pool of strings and for any string that
          // contains the substring `q`, add it to the `matches` array
          $.each(strs, function(i, str) {
            if (substrRegex.test(str)) {
              matches.push(str);
            }
          });
          cb(matches);
        };
      };
      
      var states = [];
      $.ajax({
          url: 'https://baconipsum.com/api/?type=meat-and-filler',
          type: 'get'
      }).done(function(data) {
        $('.typeahead').one().typeahead({
            hint: true,
            highlight: true,
            minLength: 1
          },
          {
            name: 'states',
            source: substringMatcher(data)
          });
      })
      

})(jQuery);
.tt-query, /* UPDATE: newer versions use tt-input instead of tt-query */
.tt-hint {
    width: 396px;
    height: 30px;
    padding: 8px 12px;
    font-size: 24px;
    line-height: 30px;
    border: 2px solid #ccc;
    border-radius: 8px;
    outline: none;
}

.tt-query { /* UPDATE: newer versions use tt-input instead of tt-query */
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}

.tt-hint {
    color: #999;
}

.tt-menu { /* UPDATE: newer versions use tt-menu instead of tt-dropdown-menu */
    width: 422px;
    margin-top: 12px;
    padding: 8px 0;
    background-color: #fff;
    border: 1px solid #ccc;
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 8px;
    box-shadow: 0 5px 10px rgba(0,0,0,.2);
}

.tt-suggestion {
    padding: 3px 20px;
    font-size: 18px;
    line-height: 24px;
    cursor: pointer;
}

.tt-suggestion:hover {
    color: #f0f0f0;
    background-color: #0097cf;
}

.tt-suggestion p {
    margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script>

<input class="typeahead" type="text" placeholder="where ?">

Ali Karimi
fonte
-1
 $('#runnerquery').typeahead({
        source: function (query, result) {
            $.ajax({
                url: "db.php",
                data: 'query=' + query,            
                dataType: "json",
                type: "POST",
                success: function (data) {
                    result($.map(data, function (item) {
                        return item;
                    }));
                }
            });
        },
        updater: function (item) {
        //selectedState = map[item].stateCode;

       // Here u can obtain the selected suggestion from the list


        alert(item);
            }

    }); 

 //Db.php file
<?php       
$keyword = strval($_POST['query']);
$search_param = "{$keyword}%";
$conn =new mysqli('localhost', 'root', '' , 'TableName');

$sql = $conn->prepare("SELECT * FROM TableName WHERE name LIKE ?");
$sql->bind_param("s",$search_param);            
$sql->execute();
$result = $sql->get_result();
if ($result->num_rows > 0) {
    while($row = $result->fetch_assoc()) {
    $Resut[] = $row["name"];
    }
    echo json_encode($Result);
}
$conn->close();

?>

Mohamed Ayed
fonte