web-dev-qa-db-fra.com

Comment puis-je personnaliser le format des résultats du plug-in Autocomplete?

J'utilise le plug-in de saisie semi-automatique de jQuery UI . Existe-t-il un moyen de mettre en évidence la séquence de caractères de recherche dans les résultats de la liste déroulante?

Par exemple, si j'ai "foo bar" comme donnée et que je tape "foo", j'aurai " foo bar" dans le menu déroulant, comme ça:

“Breakfast” appears after “Bre” is typed with “Bre” having a bold type and “akfast” having a light one.

167
dev.e.loper

Autocomplete with live suggestion

Oui, vous le pouvez si vous complétez automatiquement la mise à jour automatique.

Dans le widget autocomplete inclus dans la v1.8rc3 de l'interface utilisateur de jQuery, la fenêtre contextuelle de suggestions est créée dans la fonction _renderMenu du widget autocomplete. Cette fonction est définie comme ceci:

_renderMenu: function( ul, items ) {
    var self = this;
    $.each( items, function( index, item ) {
        self._renderItem( ul, item );
    });
},

La fonction _renderItem est définie comme suit:

_renderItem: function( ul, item) {
    return $( "<li></li>" )
        .data( "item.autocomplete", item )
        .append( "<a>" + item.label + "</a>" )
        .appendTo( ul );
},

Donc, ce que vous devez faire, c'est remplacer _renderItem fn par votre propre création qui produit l'effet souhaité. Cette technique, qui redéfinit une fonction interne dans une bibliothèque, que j’ai appris à apprendre, s’appelle monkey-patching . Voici comment je l'ai fait:

  function monkeyPatchAutocomplete() {

      // don't really need this, but in case I did, I could store it and chain
      var oldFn = $.ui.autocomplete.prototype._renderItem;

      $.ui.autocomplete.prototype._renderItem = function( ul, item) {
          var re = new RegExp("^" + this.term) ;
          var t = item.label.replace(re,"<span style='font-weight:bold;color:Blue;'>" + 
                  this.term + 
                  "</span>");
          return $( "<li></li>" )
              .data( "item.autocomplete", item )
              .append( "<a>" + t + "</a>" )
              .appendTo( ul );
      };
  }

Appelez cette fonction une fois dans $(document).ready(...).

Maintenant, c'est un hack, parce que:

  • il y a un objet regexp créé pour chaque élément rendu dans la liste. Cette expression rationnelle obj doit être réutilisée pour tous les éléments.

  • il n'y a pas de classe css utilisée pour le formatage de la pièce terminée. C'est un style en ligne.
    Cela signifie que si vous aviez plusieurs compléments automatiques sur la même page, ils recevraient tous le même traitement. Un style CSS résoudrait ce problème.

... mais cela illustre la technique principale, et cela fonctionne pour vos besoins de base.

alt text

exemple de travail mis à jour: http://output.jsbin.com/qixaxinuhe


Pour conserver la casse des chaînes de correspondance, par opposition à la casse des caractères saisis, utilisez cette ligne:

var t = item.label.replace(re,"<span style='font-weight:bold;color:Blue;'>" + 
          "$&" + 
          "</span>");

En d'autres termes, à partir du code original ci-dessus, il vous suffit de remplacer this.term Par "$&".


[~ # ~] éditer [~ # ~]
Les modifications ci-dessus tous les widget de saisie semi-automatique de la page. Si vous voulez en changer un seul, voyez cette question:
Comment patcher * une seule * instance de saisie semi-automatique sur une page?

231
Cheeso

cela fonctionne aussi:

       $.ui.autocomplete.prototype._renderItem = function (ul, item) {
            item.label = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
            return $("<li></li>")
                    .data("item.autocomplete", item)
                    .append("<a>" + item.label + "</a>")
                    .appendTo(ul);
        };

une combinaison des réponses de @ Jörn Zaefferer et de @ Cheeso.

65
Raj

Super utile. Je vous remercie. +1.

Voici une version allégée qui effectue un tri sur "String doit commencer par le terme":

function hackAutocomplete(){

    $.extend($.ui.autocomplete, {
        filter: function(array, term){
            var matcher = new RegExp("^" + term, "i");

            return $.grep(array, function(value){
                return matcher.test(value.label || value.value || value);
            });
        }
    });
}

hackAutocomplete();
8
orolo

Voilà, un exemple complet fonctionnel:

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Autocomplete - jQuery</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css">
</head>
<body>
<form id="form1" name="form1" method="post" action="">
  <label for="search"></label>
  <input type="text" name="search" id="search" />
</form>

<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js"></script>
<script>
$(function(){

$.ui.autocomplete.prototype._renderItem = function (ul, item) {
    item.label = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
    return $("<li></li>")
            .data("item.autocomplete", item)
            .append("<a>" + item.label + "</a>")
            .appendTo(ul);
};


var availableTags = [
    "JavaScript",
    "ActionScript",
    "C++",
    "Delphi",
    "Cobol",
    "Java",
    "Ruby",
    "Python",
    "Perl",
    "Groove",
    "LISP",
    "Pascal",
    "Assembly",
    "Cliper",
];

$('#search').autocomplete({
    source: availableTags,
    minLength: 3
});


});
</script>
</body>
</html>

J'espère que cela t'aides

6
Fabio Nolasco

jQueryUI 1.9.0 modifie le fonctionnement de _renderItem.

Le code ci-dessous prend en compte cette modification et montre également comment je faisais la correspondance en surbrillance à l'aide du plugin jQuery Autocomplete de Jörn Zaefferer. Il mettra en évidence tous les termes individuels dans le terme de recherche global.

Depuis que je suis passé à Knockout et jqAuto, j’ai trouvé que c’était un moyen beaucoup plus simple de styliser les résultats.

function monkeyPatchAutocomplete() {
   $.ui.autocomplete.prototype._renderItem = function (ul, item) {

      // Escape any regex syntax inside this.term
      var cleanTerm = this.term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

      // Build pipe separated string of terms to highlight
      var keywords = $.trim(cleanTerm).replace('  ', ' ').split(' ').join('|');

      // Get the new label text to use with matched terms wrapped
      // in a span tag with a class to do the highlighting
      var re = new RegExp("(" + keywords + ")", "gi");
      var output = item.label.replace(re,  
         '<span class="ui-menu-item-highlight">$1</span>');

      return $("<li>")
         .append($("<a>").html(output))
         .appendTo(ul);
   };
};

$(function () {
   monkeyPatchAutocomplete();
});
6
79IT

Voici un rappel de la solution de Ted de Koning. Il comprend :

  • Recherche insensible à la casse
  • Trouver plusieurs occurrences de la chaîne recherchée
$.ui.autocomplete.prototype._renderItem = function (ul, item) {

    var sNeedle     = item.label;
    var iTermLength = this.term.length; 
    var tStrPos     = new Array();      //Positions of this.term in string
    var iPointer    = 0;
    var sOutput     = '';

    //Change style here
    var sPrefix     = '<strong style="color:#3399FF">';
    var sSuffix     = '</strong>';

    //Find all occurences positions
    tTemp = item.label.toLowerCase().split(this.term.toLowerCase());
    var CharCount = 0;
    tTemp[-1] = '';
    for(i=0;i<tTemp.length;i++){
        CharCount += tTemp[i-1].length;
        tStrPos[i] = CharCount + (i * iTermLength) + tTemp[i].length
    }

    //Apply style
    i=0;
    if(tStrPos.length > 0){
        while(iPointer < sNeedle.length){
            if(i<=tStrPos.length){
                //Needle
                if(iPointer == tStrPos[i]){
                    sOutput += sPrefix + sNeedle.substring(iPointer, iPointer + iTermLength) + sSuffix;
                    iPointer += iTermLength;
                    i++;
                }
                else{
                    sOutput += sNeedle.substring(iPointer, tStrPos[i]);
                    iPointer = tStrPos[i];
                }
            }
        }
    }


    return $("<li></li>")
        .data("item.autocomplete", item)
        .append("<a>" + sOutput + "</a>")
        .appendTo(ul);
};
3
Pierre

pour un moyen encore plus simple, essayez ceci:

$('ul: li: a[class=ui-corner-all]').each (function (){      
 //grab each text value 
 var text1 = $(this).text();     
 //grab user input from the search box
 var val = $('#s').val()
     //convert 
 re = new RegExp(val, "ig") 
 //match with the converted value
 matchNew = text1.match(re);
 //Find the reg expression, replace it with blue coloring/
 text = text1.replace(matchNew, ("<span style='font-weight:bold;color:green;'>")  + matchNew +    ("</span>"));

    $(this).html(text)
});
  }
3
Aaron

Voici une version qui ne nécessite aucune expression régulière et qui correspond à plusieurs résultats dans l’étiquette.

$.ui.autocomplete.prototype._renderItem = function (ul, item) {
            var highlighted = item.label.split(this.term).join('<strong>' + this.term +  '</strong>');
            return $("<li></li>")
                .data("item.autocomplete", item)
                .append("<a>" + highlighted + "</a>")
                .appendTo(ul);
};
2
Ted de Koning

Jetez un coup d’œil à la démo de combobox, elle inclut la mise en évidence des résultats: http://jqueryui.com/demos/autocomplete/#combobox

La regex utilisée ici traite également des résultats HTML.

1
Jörn Zaefferer

Voici ma version:

  • Utilise des fonctions DOM au lieu de RegEx pour rompre les chaînes/injecter des balises span
  • Seule la saisie semi-automatique spécifiée est affectée, mais pas toutes.
  • Fonctionne avec l'interface utilisateur version 1.9.x
function highlightText(text, $node) {
    var searchText = $.trim(text).toLowerCase(),
        currentNode = $node.get(0).firstChild,
        matchIndex,
        newTextNode,
        newSpanNode;
    while ((matchIndex = currentNode.data.toLowerCase().indexOf(searchText)) >= 0) {
        newTextNode = currentNode.splitText(matchIndex);
        currentNode = newTextNode.splitText(searchText.length);
        newSpanNode = document.createElement("span");
        newSpanNode.className = "highlight";
        currentNode.parentNode.insertBefore(newSpanNode, currentNode);
        newSpanNode.appendChild(newTextNode);
    }
}
$("#autocomplete").autocomplete({
    source: data
}).data("ui-autocomplete")._renderItem = function (ul, item) {
    var $a = $("<a></a>").text(item.label);
    highlightText(this.term, $a);
    return $("<li></li>").append($a).appendTo(ul);
};

Mettez en surbrillance l'exemple de texte correspondant

1
Salman A

vous pouvez utiliser le code suivant:

lib:

$.widget("custom.highlightedautocomplete", $.ui.autocomplete, {
    _renderItem: function (ul, item) {
        var $li = $.ui.autocomplete.prototype._renderItem.call(this,ul,item);
        //any manipulation with li
        return $li;
    }
});

et logique:

$('selector').highlightedautocomplete({...});

il crée un widget personnalisé pouvant remplacer _renderItem sans écraser _renderItem du prototype du plugin original.

dans mon exemple, également utilisé la fonction de rendu d'origine pour simplifier le code

c'est important si vous voulez utiliser un plugin à différents endroits avec une vue différente de la saisie semi-automatique et que vous ne voulez pas casser votre code.

1
E.Monogarov

Pour prendre en charge plusieurs valeurs, ajoutez simplement la fonction suivante:

function getLastTerm( term ) {
  return split( term ).pop();
}

var t = String(item.value).replace(new RegExp(getLastTerm(this.term), "gi"), "<span class='ui-state-highlight'>$&</span>");
0
ZaieN

Si vous utilisez plutôt le plug-in tiers, il dispose d'une option de surbrillance: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(voir l'onglet Options)

0
Brian Luft