ejemplo de arranque de twitter typeahead ajax

280

Estoy tratando de encontrar un ejemplo que funcione del elemento de tipo de arranque de Twitter Bootstrap que hará una llamada ajax para completar su menú desplegable.

Tengo un ejemplo de autocompletar jquery que funciona que define la url de ajax y cómo procesar la respuesta

<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];
                }
            );
       ..

¿Qué necesito cambiar para convertir esto al ejemplo de 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];
                }
            );
       ..

Voy a esperar a que se resuelva el problema ' Agregar soporte de fuentes remotas para typeahead '.

esmeralda
fuente
Para ser más específico, me pregunto cómo se correlacionan las opciones de autocompletar y la función de manejo de resultados con las opciones de textahead. ¿Existe un conjunto de funciones definidas de manejo de resultados de textalert que se pueden anular, o el método nombrado se hereda de la API jquery subyacente?
emeraldjava
1
¿Podría marcar la respuesta de Stijn Van Bael como la correcta ahora? La respuesta de bogert solo funciona para versiones desactualizadas de Bootstrap.
Giles Roberts

Respuestas:

302

Editar: typeahead ya no está incluido en Bootstrap 3. Echa un vistazo:

A partir de Bootstrap 2.1.0 hasta 2.3.2, puede hacer esto:

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

Para consumir datos JSON como este:

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

Tenga en cuenta que los datos JSON deben ser del tipo mime correcto (aplicación / json) para que jQuery los reconozca como JSON.

Stijn Van Bael
fuente
3
Como en la bifurcación Typeahead, los datos deben ser una matriz de cadenas JSON y el tipo de contenido debe ser application / json.
Stijn Van Bael
9
¿Puede 2.1 usar json que no es solo una matriz de cadenas? Necesito un valor para el usuario y usar una identificación para realizar un procesamiento adicional. ¿Es eso posible sin elegir un tenedor personalizado?
Anton
2
@Stijin ¿Hay algún ejemplo de cómo se usaría esa función anónima aquí, para procesar una identificación para una opción mostrada? ¡Gracias!
Acyra
1
Me gustaría señalar que el uso de este método da como resultado una llamada AJAX que se realiza para cada pulsación de tecla en la entrada. Si el servidor está devolviendo datos esencialmente estáticos (es decir, en realidad no está haciendo nada con la consulta), entonces esto puede ser un desperdicio.
Dologan
2
¿Por qué usar en getlugar de getJSON? Parece más apropiado
greg0ire
119

Puede usar la bifurcación BS Typeahead que admite llamadas ajax. Entonces podrás escribir:

$('.typeahead').typeahead({
    source: function (typeahead, query) {
        return $.get('/typeahead', { query: query }, function (data) {
            return typeahead.process(data);
        });
    }
});
bogert
fuente
1
La "suposición inteligente" de jQuery para el tipo de retorno de los datos POST no funcionaba cuando regresé, por ejemplo ["aardvark", "apple"],. Tuve que establecer explícitamente el dataTypeparámetro en la $.postllamada. Ver jQuery.post () .
Rusty Fausak
1
@rfausak Alternativamente, configure el Content-typeencabezado enapplication/json
Rusty Fausak
23
Estoy obteniendo TypeError no capturado: no se puede llamar al método 'toLowerCase' de undefined
Krishnaprasad Varma
En el enlace que enviaste, ni siquiera estoy sourceejecutando la función.
James
8
¡Buena respuesta! En su lugar, usaría una solicitud GET, solo para cumplir con los estándares REST.
Mauro
72

A partir de 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);
            }
        });
    }
});

Ahora puede hacer un código unificado, colocando enlaces "json-request" en su código HTML.

Thantifaxath
fuente
11
Pero lo cambiaría para usarlo $(this)[0].$element.data('link').
Andrew Ellis
othis.$element.data('link')
Richard87
51

Todas las respuestas se refieren a BootStrap 2 typeahead, que ya no está presente en BootStrap 3.

Para cualquier otra persona dirigida aquí que busque un ejemplo de AJAX usando el nuevo Twitter post-Bootstrap typeahead.js , aquí hay un ejemplo de trabajo. La sintaxis es un poco 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 ejemplo utiliza tanto la sugerencia síncrona (la llamada a processSync ) como la asíncrona, por lo que verá que algunas opciones aparecen de inmediato y luego se agregan otras. Puedes usar uno u otro.

Hay muchos eventos vinculables y algunas opciones muy potentes, incluido el trabajo con objetos en lugar de cadenas, en cuyo caso usaría su propia función de visualización personalizada para representar sus elementos como texto.

Jonathan Lidbeck
fuente
1
Gracias. Una pregunta más: con processAsync obtengo "TypeError: sugerencias.slice no es una función". ¿Cómo se vería también el JSON devuelto? Aquí está mi mejor conjetura: {: sugerencias => ["Cosa 1", "Cosa 2", "Cosa 3"]}
usuario1515295
1
Asegúrese de devolver una cadena JSON válida. La función de sugerencia de AJAX debe devolver una matriz de cadenas, por ejemplo ["Thing 1","Thing 2"], o con una función de visualización personalizada, una matriz de objetos de acuerdo con sus necesidades, por ejemplo[{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}]
Jonathan Lidbeck
Regreso [{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}], ahora quiero mostrar dos columnas en el menú desplegable de mecanografía con identificación y etiqueta. ¿Cómo puedo hacer eso?
Vishal
2
¡¡¡DIOS MÍO!!! Estaba buscando en los últimos 3 días que nadie mencionó sobre esto. Estaba probando con la función de sincronización hasta ahora. GRACIAS DUDE !!
Gilson PJ
Gracias ! Funciona muy bien con bootstrap 4.3 y jquery 3.4. Pero, las opciones enumeradas no se resaltan cuando el mouse se desplaza sobre él. Pensé que se suponía que era parte de la mecanografía en sí misma.
Binita Bharati
25

He aumentado el plugin Bootstrap typeahead original con capacidades ajax. Muy facil de usar:

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

Aquí está el repositorio de github: Ajax-Typeahead

Paul Warelis
fuente
He mirado el código de Gudbergur; francamente, me gustó este mejor. Es un poco más amigable y ofrece más funcionalidad. Buen trabajo Paul! Lo único que sugeriría es que en su archivo README le recuerde al usuario que necesita analizar sus datos JSON en JS para que su código pueda usarlo correctamente. Supuse que lo estabas analizando por mí, así que eso me colgó un poco. De lo contrario, muy bien, gracias! :)
Bane
3
Su servidor devuelve una cadena en lugar de un objeto JSON. $ .ajax () de jQuery se usa para hacer la llamada, y se encarga del análisis.
Paul Warelis
1
absolutamente correcto, gracias por la captura! :) Este complemento funciona muy bien.
Bane
Hola, ¿cómo debería ser el lado del servidor JSON? Me estoy poniendo Uncaught TypeError: Cannot read property 'length' of undefined . Estoy usando json_encode($array)y enviando encabezados correctos ( 'Content-Type: application/json; charset=utf-8'). Versión jqueryjQuery v1.9.1
Kyslik
5

Hice algunas modificaciones en 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")`

y agregue el siguiente CSS

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

Funciona perfecto

bmoers
fuente
¿Qué versión de jquery ui min estás usando?
emeraldjava
Si necesita esto para jQuery 1.7.1 y jQuery UI 1.8.16, he creado un GIST basado en la corrección anterior que muestra dónde cambiar el archivo jQuery UI. gist.github.com/1884819 - las líneas se comentan con // modificado
Richard Hollis
Esta es una pregunta / respuesta bastante antigua, pero solo quiero decir que siempre es una mala práctica cambiar el código de componentes de terceros. Tendrá que volver a visitar todos los cambios cada vez que los actualice. En este caso particular, se pueden heredar widgets jQuery, que es una forma mucho más segura de personalizarlos. Básicamente, crea tu propio widget, hereda del núcleo (el autocompletado en este caso) y da rienda suelta a tu imaginación. :)
AlexCode
3

Estoy usando este metodo

$('.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
fuente
Sería bueno si pudiera agregar alguna explicación a su respuesta. Por ejemplo, ¿cuál es la diferencia de su solución en comparación con las soluciones presentadas en las respuestas ya existentes?
tocar la bocina el
2

Uno puede hacer llamadas usando Bootstrap. La versión actual no tiene ningún problema de actualización de la fuente. Problemas para actualizar la fuente de datos de typeahead de Bootstrap con respuesta posterior , es decir, la fuente de bootstrap una vez actualizada puede modificarse nuevamente.

Consulte a continuación para ver un ejemplo:

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
fuente
2

Para aquellos que buscan una versión en coffeescript de la respuesta aceptada:

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

Revisé esta publicación y todo no quería funcionar correctamente y, finalmente, reconstruí los bits de algunas respuestas, así que tengo una demostración 100% funcional y la pegaré aquí como referencia: pegue esto en un archivo php y asegúrese de que las inclusiones estén en el lugar correcto.

<?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
fuente
2

Intente esto si su servicio no devuelve el encabezado de tipo de contenido json / aplicación correcto:

$('.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
fuente
1

ACTUALIZACIÓN: modifiqué mi código usando esto bifurcación

También en lugar de usar $ .cada uno cambié a $ .map como lo sugirió 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) {

    }
});

Sin embargo, me encuentro con algunos problemas al obtener

TypeError no capturado: no se puede llamar al método 'toLowerCase' de undefined

como puedes ver en una publicación más reciente, estoy tratando de descubrir aquí

Espero que esta actualización sea de alguna ayuda para usted ...

mmoscosa
fuente
Sin relación con OP: en su Array.maplugar, usaría $.eachy reemplazaría el contenido de toda su successfunción de devolución de llamada convar manufacturers = results.data.manufacturers.map(function (item) { return { id: item.Manufacturer.id, manufacturer: item.Manufacturer.manufacturer } });
Tomislav Markovski
gracias @TomislavMarkovski Modifiqué mi código como sugieres.
mmoscosa
0

No tengo un ejemplo de trabajo para ti ni tengo una solución muy limpia, pero déjame decirte lo que he encontrado.

Si observa el código de JavaScript para TypeAhead, se ve así:

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

Este código utiliza el método jQuery "grep" para hacer coincidir un elemento en la matriz fuente. No vi ningún lugar al que pudiera conectar una llamada AJAX, por lo que no hay una solución "limpia" para esto.

Sin embargo, una forma un tanto hacky de hacerlo es aprovechar la forma en que funciona el método grep en jQuery. El primer argumento para grep es la matriz de origen y el segundo argumento es una función que se utiliza para hacer coincidir la matriz de origen (observe que Bootstrap llama al "emparejador" que proporcionó cuando lo inicializó). Lo que podría hacer es establecer la fuente en una matriz ficticia de un elemento y definir el emparejador como una función con una llamada AJAX. De esa manera, ejecutará la llamada AJAX solo una vez (ya que su matriz fuente solo tiene un elemento).

Esta solución no solo es hacky, sino que sufrirá problemas de rendimiento ya que el código TypeAhead está diseñado para realizar una búsqueda en cada pulsación de tecla (las llamadas AJAX en realidad solo deberían ocurrir cada pocas pulsaciones de tecla o después de una cierta cantidad de tiempo inactivo). Mi consejo es que lo intente, pero quédese con una biblioteca de autocompletado diferente o solo use esto para situaciones que no sean AJAX si tiene algún problema.

Aamer Abbas
fuente
0

cuando use ajax, intente en $.getJSON()lugar de $.get()si tiene problemas con la visualización correcta de los resultados.

En mi caso, obtuve solo el primer carácter de cada resultado cuando lo usé $.get(), aunque lo json_encode()hice en el lado del servidor.

larsbo
fuente
0

Yo uso $().one() para resolver esto; Cuando se carga la página, envío ajax al servidor y espero a que termine. Luego pase el resultado a la función. $().one()es importante. Porque forzar typehead.js para adjuntar a la entrada una vez. Perdón por la mala escritura.

(($) => {
    
    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
fuente
-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
fuente