twitter bootstrap typeahead ajax exemple

280

J'essaie de trouver un exemple de travail de l' élément twitter bootstrap typeahead qui fera un appel ajax pour remplir sa liste déroulante.

J'ai un exemple de saisie semi-automatique de travail existant qui définit l'URL ajax et comment traiter la réponse

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

Que dois-je changer pour convertir cela en l'exemple 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];
                }
            );
       ..

Je vais attendre que le problème « Ajouter le support des sources distantes pour typeahead » soit résolu.

emeraldjava
la source
Pour être plus précis, je me demande comment les options de saisie semi-automatique et la fonction de gestion des résultats correspondent aux options de textahead? Existe-t-il un ensemble de fonctions de gestion des résultats textalert définies qui peuvent être remplacées, ou la méthode nommée est-elle héritée de l'api jquery sous-jacente?
emeraldjava
1
Pourriez-vous marquer la réponse de Stijn Van Bael comme la bonne maintenant? La réponse de bogert ne fonctionne que pour les versions obsolètes de Bootstrap.
Giles Roberts

Réponses:

302

Edit: typeahead n'est plus inclus dans Bootstrap 3. Découvrez:

De Bootstrap 2.1.0 à 2.3.2, vous pouvez le faire:

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

Pour consommer des données JSON comme ceci:

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

Notez que les données JSON doivent être du bon type MIME (application / json) afin que jQuery les reconnaisse comme JSON.

Stijn Van Bael
la source
3
Comme dans le fork Typeahead, les données doivent être un tableau JSON de chaînes et le type de contenu doit être application / json.
Stijn Van Bael du
9
2.1 peut-il utiliser json qui n'est pas seulement un tableau de chaînes? j'ai besoin d'une valeur pour l'utilisateur et d'utiliser un identifiant pour poursuivre le traitement. Est-ce possible sans ramasser une fourche personnalisée?
Anton
2
@Stijin Y a-t-il des exemples de la façon dont cette fonction anonyme serait utilisée ici, pour traiter un identifiant pour une option affichée? Merci!
Acyra
1
Je tiens à souligner que l'utilisation de cette méthode entraîne la création d'un appel AJAX pour chaque frappe sur l'entrée. Si le serveur renvoie des données essentiellement statiques (c'est-à-dire qu'il ne fait vraiment rien avec la requête), cela peut être assez inutile.
Dologan
2
pourquoi utiliser getau lieu de getJSON? Cela semble plus approprié.
greg0ire
119

Vous pouvez utiliser le fork BS Typeahead qui prend en charge les appels ajax. Vous pourrez alors écrire:

$('.typeahead').typeahead({
    source: function (typeahead, query) {
        return $.get('/typeahead', { query: query }, function (data) {
            return typeahead.process(data);
        });
    }
});
bogert
la source
1
La «supposition intelligente» de jQuery pour le type de retour des données POST ne fonctionnait pas lorsque je suis revenu, par exemple ["aardvark", "apple"],. J'ai dû définir explicitement le dataTypeparamètre dans l' $.postappel. Voir jQuery.post () .
Rusty Fausak
1
@rfausak Alternativement, définissez l'en- Content-typetête surapplication/json
Rusty Fausak
23
je reçois TypeError Uncaught: Impossible d'appeler la méthode 'toLowerCase' d'undefined
Krishnaprasad Varma
Dans le lien que vous avez envoyé, je n'obtiens même pas la sourcefonction à exécuter.
James
8
Bonne réponse! J'utiliserais une demande GET à la place, juste pour répondre aux normes REST.
Mauro
72

À 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);
            }
        });
    }
});

Vous pouvez maintenant créer un code unifié, en plaçant des liens "json-request" dans votre code HTML.

Thantifaxath
la source
11
Mais je le changerais pour l'utiliser $(this)[0].$element.data('link').
Andrew Ellis
outhis.$element.data('link')
Richard87
51

Toutes les réponses se réfèrent à la tête de frappe BootStrap 2, qui n'est plus présente dans BootStrap 3.

Pour toute autre personne dirigée ici à la recherche d'un exemple AJAX en utilisant le nouveau typeahead.js Twitter post-Bootstrap , voici un exemple de travail. La syntaxe est un peu différente:

$('#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);
      }
    });
  }
});

Cet exemple utilise à la fois la suggestion synchrone (l'appel à processSync ) et asynchrone, vous verrez donc certaines options apparaître immédiatement, puis d'autres seront ajoutées. Vous pouvez simplement utiliser l'un ou l'autre.

Il existe de nombreux événements pouvant être liés et certaines options très puissantes, notamment le travail avec des objets plutôt qu'avec des chaînes, auquel cas vous utiliseriez votre propre fonction d' affichage personnalisée pour rendre vos éléments sous forme de texte.

Jonathan Lidbeck
la source
1
Je vous remercie. Une autre question: avec processAsync, je reçois "TypeError: suggestions.slice n'est pas une fonction." À quoi ressemblerait le JSON retourné? Voici ma meilleure conjecture: {: suggestions => ["Thing 1", "Thing 2", "Thing 3"]}
user1515295
1
Assurez-vous de renvoyer une chaîne JSON valide. Votre fonction de suggestion AJAX devrait renvoyer un tableau de chaînes, par exemple ["Thing 1","Thing 2"], ou avec une fonction d'affichage personnalisée, un tableau d'objets en fonction de vos besoins, par exemple[{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}]
Jonathan Lidbeck
Je reviens [{"id":1,"label":"Foo"},{"id":2,"label":"Bar"}], maintenant je veux montrer deux colonnes dans la liste déroulante typeahead avec id et label. Comment puis je faire ça?
Vishal
2
MON DIEU!!! Je cherchais depuis 3 jours personne n'a mentionné à ce sujet. Je testais avec la fonction de synchronisation jusqu'à présent. MERCI MEC!!
Gilson PJ
Merci ! Fonctionne très bien avec bootstrap 4.3 et jquery 3.4. Mais, les options répertoriées ne sont pas mises en surbrillance lorsque la souris survole. Je pensais que c'était censé faire partie de la tête de police elle-même.
Binita Bharati
25

J'ai augmenté le plugin Bootstrap typeahead original avec des capacités ajax. Très simple d'utilisation:

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

Voici le dépôt github: Ajax-Typeahead

Paul Warelis
la source
J'ai regardé le code de Gudbergur; franchement, j'ai préféré celui-ci. C'est un peu plus convivial et offre plus de fonctionnalités. Bon travail Paul! La seule chose que je suggérerais est dans votre fichier README de rappeler à l'utilisateur qu'il doit analyser ses données JSON dans JS pour que votre code puisse l'utiliser correctement. J'avais supposé que vous le analysiez pour moi, ce qui m'a suspendu un peu. Sinon, plutôt sympa, merci! :)
Bane
3
Votre serveur renvoie une chaîne au lieu d'un objet JSON. $ .ajax () de jQuery est utilisé pour effectuer l'appel, et il prend en charge l'analyse.
Paul Warelis
1
tout à fait correct, merci pour la capture! :) Ce plugin fonctionne très bien.
Bane
Bonjour, à quoi devrait JSONressembler le côté serveur ? Je reçois Uncaught TypeError: Cannot read property 'length' of undefined . J'utilise json_encode($array)et envoie des en-têtes à droite ( 'Content-Type: application/json; charset=utf-8'). version jqueryjQuery v1.9.1
Kyslik
5

J'ai fait quelques modifications sur 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")`

et ajouter css suivant

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

Fonctionne parfaitement.

bmoers
la source
quelle version de jquery ui min utilisez-vous?
emeraldjava
Si vous en avez besoin pour jQuery 1.7.1 et jQuery UI 1.8.16, j'ai créé un GIST basé sur le correctif ci-dessus qui montre où changer le fichier jQuery UI. gist.github.com/1884819 - les lignes sont commentées avec // modifié
Richard Hollis
C'est une question / réponse assez ancienne mais je veux juste dire que c'est toujours une mauvaise pratique de changer le code des composants tiers. Vous devrez revoir toutes les modifications chaque fois que vous les mettez à niveau. Dans ce cas particulier, les widgets jQuery peuvent être hérités, ce qui est un moyen beaucoup plus sûr de les personnaliser. Donc, fondamentalement, créez votre propre widget, héritez du noyau (la saisie semi-automatique dans ce cas) et laissez libre cours à votre imagination! :)
AlexCode
3

J'utilise cette méthode

$('.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
la source
Ce serait bien si vous pouviez ajouter quelques explications à votre réponse. Par exemple, quelle est la différence de votre solution par rapport aux solutions présentées dans les réponses déjà existantes?
klaxonner
2

On peut faire des appels en utilisant Bootstrap. La version actuelle ne présente aucun problème de mise à jour source. Problème de mise à jour de la source de données de type Bootstrap avec post-réponse , c'est-à-dire que la source de bootstrap une fois mise à jour peut être à nouveau modifiée.

Veuillez vous référer ci-dessous pour un exemple:

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
la source
2

À ceux qui recherchent une version en coffeescript de la réponse acceptée:

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

J'ai parcouru ce post et tout ne voulait pas fonctionner correctement et j'ai finalement reconstitué les bits de quelques réponses, j'ai donc une démo de travail à 100% et je vais la coller ici pour référence - collez-la dans un fichier php et assurez-vous que les inclus sont dans le bon endroit.

<?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
la source
2

Essayez ceci si votre service ne renvoie pas le bon en-tête de type de contenu application / 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
la source
1

MISE À JOUR: j'ai modifié mon code en utilisant cette fourchette

également au lieu d'utiliser $ .each, je suis passé à $ .map comme suggéré par 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) {

    }
});

Cependant, je rencontre des problèmes en obtenant

TypeError non capturé: impossible d'appeler la méthode «toLowerCase» de non défini

comme vous pouvez le voir sur un nouveau post, j'essaie de comprendre ici

j'espère que cette mise à jour vous sera utile ...

mmoscosa
la source
Sans rapport avec OP: j'utiliserais à la Array.mapplace $.eachet remplacerais le contenu de toute votre successfonction de rappel parvar manufacturers = results.data.manufacturers.map(function (item) { return { id: item.Manufacturer.id, manufacturer: item.Manufacturer.manufacturer } });
Tomislav Markovski
merci @TomislavMarkovski J'ai modifié mon code comme vous le suggérez.
mmoscosa
0

Je n'ai pas d'exemple de travail pour vous ni de solution très propre, mais laissez-moi vous dire ce que j'ai trouvé.

Si vous regardez le code javascript de TypeAhead, il ressemble à ceci:

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

Ce code utilise la méthode jQuery "grep" pour faire correspondre un élément du tableau source. Je n'ai pas vu d'endroits où vous pourriez accrocher un appel AJAX, donc il n'y a pas de solution "propre" à cela.

Cependant, une façon quelque peu hacky que vous pouvez faire est de tirer parti de la façon dont la méthode grep fonctionne dans jQuery. Le premier argument de grep est le tableau source et le second argument est une fonction qui est utilisée pour faire correspondre le tableau source (notez que Bootstrap appelle le "matcher" que vous avez fourni lorsque vous l'avez initialisé). Ce que vous pourriez faire est de définir la source sur un tableau factice à un élément et de définir le matcher comme une fonction contenant un appel AJAX. De cette façon, il exécutera l'appel AJAX une seule fois (puisque votre tableau source ne contient qu'un seul élément).

Cette solution est non seulement hacky, mais elle souffrira de problèmes de performances car le code TypeAhead est conçu pour effectuer une recherche à chaque pression de touche (les appels AJAX ne devraient vraiment se produire que sur quelques touches ou après un certain temps d'inactivité). Mon conseil est de l'essayer, mais restez avec une autre bibliothèque de saisie semi-automatique ou utilisez-la uniquement pour les situations non AJAX si vous rencontrez des problèmes.

Aamer Abbas
la source
0

lorsque vous utilisez ajax, essayez $.getJSON()plutôt que $.get()si vous avez des problèmes avec l'affichage correct des résultats.

Dans mon cas, je n'ai obtenu que le premier caractère de chaque résultat lorsque j'ai utilisé $.get(), bien que j'aie utilisé json_encode()côté serveur.

larsbo
la source
0

j'utilise $().one() pour résoudre cela; Lorsque la page est chargée, j'envoie ajax au serveur et j'attends de terminer. Passez ensuite le résultat à la fonction. $().one()est important. Car forcez typehead.js à être attaché une fois. désolé pour une mauvaise écriture.

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