Twitters Typeahead and Ajax

Twitters JQuery-Autocompleter Typeahead (nicht Bootstrap Typeahead, welcher in Bootstrap 3 auch nicht mehr integriert ist) ist ein recht praktikabler Autocompleter den man mit ein paar Zeilen gut an seine eigenen Bedürfnisse anpassen kann. Ich zeige es hier Anhand eines Ajax Calls mit zuerst noch nicht passenden Daten für Typeahead. Um diesen jetzt mit Custom Ajax Daten zu befüllen, werden der typeahead Funktion folgende Optionen übergeben.

Remote sagt hier aus das die Daten nachgeladen werden (könnte z.B. auch eine Json Datei auf einen Server sein oder ähnliches). Remote wiederum besteht aus mehreren Parametern die befüllt werden können. Die Url gibt logischerweise nur das Ziel des Ajax Calls an. Wie man bei URL sieht stelle ich mir hier z.B. die url durch eine Variable und den Wert des Inputfelds zusammen %QUERY wird anschließend von der Funktion automatisch mit dem Wert des Inputfeldes ersetzt. Um jetzt die noch nicht ganz passenden Daten in passende Daten zu konvertieren gibt es hier auch noch das filter – Feld. Diese erwartet eine Funktion, wobei der erste Parameter die vom Server geholten Daten repräsentieren. Hier erstelle ich ganz ein ganz simples Array, welches ich anschließend zurückgebe (Twitter Doku)


        $('#input').typeahead({
            remote: {
                url: baseUrl+'?q=%QUERY',
                filter: function(parsedResponse){
                    var data = [];
                    $.each(parsedResponse, function(index, item){
                        data.push(  {
                            value: item.name,
                            tokens: [item.name],
                            name: item.name
                        });
                    });
                    return data;
                }//A function with the signature filter(parsedResponse) that transforms the response body into an array of datums. Expected to return an array of datums.
            }
        });

So hat man mit ein paar Zeilen Daten vom Server abgeholt und an seine Bedürfnisse angepasst. Für Bootstrap 3 müssen momentan noch ein paar Zeilen CSS eingefügt werden (Typeahead CSS ). Zusätzlich musste ich aber hierbei noch für die hints display: none setzen da der Hint nicht an die passende Stelle wollte. Zusätzlich musste ich für den Span die Breite auf 100% erhöhen da sonst das input Feld zu klein bleibt.


.twitter-typeahead .tt-hint
{
    display: none;
    height: 34px;
    padding: 6px 12px;
    font-size: 14px;
    line-height: 1.428571429;
    border: 1px solid transparent;
    border-radius:4px;
}

.twitter-typeahead .hint-small
{
    height: 30px;
    padding: 5px 10px;
    font-size: 12px;
    border-radius: 3px;
    line-height: 1.5;
}

.twitter-typeahead .hint-large
{
    height: 45px;
    padding: 10px 16px;
    font-size: 18px;
    border-radius: 6px;
    line-height: 1.33;
}

.twitter-typeahead .tt-query,
.twitter-typeahead .tt-hint {
    margin-bottom: 2px;
}

.tt-dropdown-menu {
    min-width: 240px;
    margin-top: 2px;
    padding: 5px 0;
    background-color: #fff;
    border: 1px solid #ccc;
    border: 1px solid rgba(0,0,0,.2);
    *border-right-width: 2px;
    *border-bottom-width: 2px;
    -webkit-border-radius: 6px;
    -moz-border-radius: 6px;
    border-radius: 6px;
    -webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
    -moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
    box-shadow: 0 5px 10px rgba(0,0,0,.2);
    -webkit-background-clip: padding-box;
    -moz-background-clip: padding;
    background-clip: padding-box;
}

.tt-suggestion {
    display: block;
    padding: 3px 20px;
}

.tt-suggestion.tt-is-under-cursor {
    color: #fff;
    background-color: #0081c2;
    background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
    background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
    background-image: -o-linear-gradient(top, #0088cc, #0077b3);
    background-image: linear-gradient(to bottom, #0088cc, #0077b3);
    background-repeat: repeat-x;
    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0)
}

.tt-suggestion.tt-is-under-cursor a {
    color: #fff;
}

.tt-suggestion p {
    margin: 0;
}

.twitter-typeahead {
    width: 100%;
}

Asynchrones Iteration Pattern

Ein nettes Pattern wenn man in JavaScript z.B. über eine Liste iterieren will, anhand deren man ajax – Calls staret. Hierbei tritt ja das Problem auf das man nicht zu viele Verbindungen aufn einmal öffnen kann. Nun bietet sich der Einfachheit wegen eine simple foreach Schleife an, bei der man pro Element abwartet bis die Antwort da ist. In jQuery würde dies dann ca so aussehen


$.ajax({
url: "url.php",
data: "data1=1",
async: false
}).done(//successhandler);

Dies führt aber zu den Problem das der Browser dadurch „steht“ (Ausnahme ist hier Firefox). Dies kann durch interne JavaScript Optimizer sogar dazuführen das eventuell ausgeführte Logik zum ein- und ausblenden erst danach geschieht (getestet mit der aktuellen Version von Google Chrome).

Abhilfe schafft hier das Asynchrone Iteration Pattern. Dies könnte wie folgt aussehen:


function iterate(){
 var data = "data1=1";
 var liste = [1,2,3,4,5,6,7,8,9];
 _next(0);
 return;   
       
 /**
  * Asynchroner Iterator über die Liste
  * @param position
  * @private
  */
  function _next(position){
      $.ajax({
          url: "test.php",
          type: 'POST',
          data: data + "&pos="+position,
      })
      .done(function(){
      //successhandler
      }).fail(function(jqXHR, textStatus, errorThrown){
      //errorhandler
     }).always(function(){
       position++;
       if(position == liste.length){
         return;
       }else{
         _next(position)
      });   
   }
}

Es wird einfach nach jeden fertigen Call, die nächste Position in der Liste aufgerufen, falls noch ein Element vorhanden ist.

Scroll to top