Come posso formattare in modo personalizzato i risultati del plug-in di completamento automatico?


Risposte:


233

Completamento automatico con suggerimento dal vivo

Sì, è possibile se si completa automaticamente la patch di scimmia.

Nel widget di completamento automatico incluso in v1.8rc3 dell'interfaccia utente di jQuery, il popup di suggerimenti viene creato nella funzione _renderMenu del widget di completamento automatico. Questa funzione è definita in questo modo:

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

La funzione _renderItem è definita in questo modo:

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

Quindi quello che devi fare è sostituire quel _renderItem fn con la tua creazione che produce l'effetto desiderato. Questa tecnica, che ridefinisce una funzione interna in una libreria, che ho imparato a conoscere, si chiama patch-monkey . Ecco come l'ho fatto:

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

Chiama quella funzione una volta dentro $(document).ready(...).

Ora, questo è un trucco, perché:

  • c'è un oggetto regexp creato per ogni elemento visualizzato nell'elenco. Quel regexp obj dovrebbe essere riutilizzato per tutti gli oggetti.

  • non esiste una classe CSS utilizzata per la formattazione della parte completata. È uno stile in linea.
    Ciò significa che se avessi più completamenti automatici nella stessa pagina, otterrebbero tutti lo stesso trattamento. Uno stile CSS risolverebbe questo.

... ma illustra la tecnica principale e funziona per i tuoi requisiti di base.

testo alternativo

esempio di lavoro aggiornato: http://output.jsbin.com/qixaxinuhe


Per preservare il caso delle stringhe di corrispondenza, anziché utilizzare il caso dei caratteri digitati, utilizzare questa riga:

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

In altre parole, a partire dal codice originale sopra, devi solo sostituirlo this.termcon "$&".


MODIFICA
Quanto sopra cambia ogni widget di completamento automatico sulla pagina. Se vuoi cambiarne solo una, vedi questa domanda:
Come patchare * solo * un'istanza di Completamento automatico su una pagina?


Grazie Cheeso. Hai un link jsbin per questo?
dev.e.loper

1
Nota che se fai catena, è importante ripristinare il contesto: oldFn.apply (this, [ul, item]);
emanaton

Grazie mille! Sarebbe fantastico se questo diventasse parte dell'interfaccia utente di jQuery.
David Ryder,

4
Una cosa che direi è che se vuoi che il risultato sia in grassetto in qualsiasi parte della stringa corrispondente (non solo all'inizio), modifica la riga RegExp in questo modo: var re = new RegExp (this.term);
David Ryder,

1
Il completamento automatico JQueryUI sembra eseguire una ricerca senza distinzione tra maiuscole e minuscole per impostazione predefinita, quindi ha senso aggiungere il flag "i" nell'oggetto RegExp. Non c'è nemmeno motivo di usare "^" nel regex come menzionato da @DavidRyder. Mi piace: var re = new RegExp(this.term, "i"); Ottimo post!
Sam,

65

questo funziona anche:

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

una combinazione delle risposte di @ Jörn Zaefferer e @ Cheeso.


Mi è piaciuto di più, perché corrisponde a tutta la parola.
atp

3
Funziona bene L'unica cosa a cui prestare attenzione è che item.label verrà sostituito. Per me, stavo ottenendo "<strong ..." nella mia casella di testo. Basta assegnare il risultato di sostituzione a un'altra variabile cancellata. Non avresti questo problema se i tuoi dati contengono una proprietà value che viene inserita nella casella di testo.
Kijana Woodard,

questo non funziona se si dispone di un completamento automatico che supporta più valori. eventuali suggerimenti?
leora,

Il modo più semplice per ottenere l'evidenziazione del testo nei risultati del completamento automatico. Ovviamente fai attenzione ai bug come sottolineato da Leora e Kijana sopra
adamst85,

@RNKushwaha ovunque prima di chiamare$().autocomplete()
Brian Leishman,

8

Super utile. Grazie. +1.

Ecco una versione leggera che ordina su "String deve iniziare con il termine":

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();

1
Grazie Orolo, stavo usando il completamento automatico in più posizioni e volevo un posto centrale in cui posso apportare la modifica per mostrare solo i risultati che iniziano con i caratteri digitati e questo è esattamente ciò di cui avevo bisogno!
dreamerkumar,

Grazie. Questa è la migliore soluzione di tutte. Funziona senza distinzione tra maiuscole e minuscole.
Aniket Kulkarni l'

7

Ecco un esempio completo funzionale:

<!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>

Spero che questo ti aiuti


6

jQueryUI 1.9.0 modifica il funzionamento di _renderItem.

Il codice qui sotto prende in considerazione questa modifica e mostra anche come stavo facendo la corrispondenza evidenziata usando il plugin di completamento automatico jQuery di Jörn Zaefferer. Evidenzierà tutti i singoli termini nel termine di ricerca generale.

Da quando ho iniziato a usare Knockout e jqAuto ho scoperto che questo è un modo molto più semplice di definire i risultati.

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

Quando cerco caratteri come '(' causa un errore ("Uncaught SyntaxError: espressione regolare non valida: / (sam | at | () /: gruppo non terminato") comunque per risolvere questo problema impedendo la collisione con regex?
Idan Shechter

Risposta fantastica! Adoro il fatto che evidenzi i termini indipendentemente da dove appaiono. Molto bello. Grazie per aver aggiornato il post. Una domanda che ho avuto riguarda la classe .ui-menu-item-highlight che usi. Questo dovrebbe essere definito da jquery-ui o dai consumatori? Ho cambiato il nome della classe per adattarmi ai miei mezzi e ho semplicemente reso audace il peso del carattere. .jqAutocompleteMatch { font-weight: bold; }
Sam,

@IdanShechter Ottimo commento. this.termPrima di eseguire qualsiasi elaborazione è necessario utilizzare una logica per sfuggire a for regex. Vedi Escape string per l'uso in regex Javascript come una delle tante risposte a come eseguire questa operazione.
Sam,

3

per un modo ancora più semplice, prova questo:

$('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

Ecco un ripasso della soluzione di Ted de Koning. Include :

  • Ricerca senza distinzione tra maiuscole e minuscole
  • Trovare molte occorrenze della stringa cercata
$.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);
};

1
Penso che stai reinventando la ruota! Perché non usi espressioni regolari che sono più veloci, più facili e più compatte di tutto questo codice?
George Mavritsakis,

2

Ecco una versione che non richiede espressioni regolari e corrisponde a più risultati nell'etichetta.

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

Questa è probabilmente la soluzione migliore, ma credo che string.split sia compatibile solo con maiuscole e minuscole.
Noel Abrahams,

Hai un modo per abbinare le parole in base alla distinzione tra maiuscole e minuscole? Perché se ho una ricerca "alfa", non evidenzierà "Alfa"
Patrick


1

Ecco la mia versione:

  • Utilizza le funzioni DOM anziché RegEx per interrompere le stringhe / iniettare i tag di span
  • È interessato solo il completamento automatico specificato, non tutti
  • Funziona con l'interfaccia utente versione 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);
};

Evidenzia l'esempio di testo corrispondente


1

puoi usare il seguente codice:

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

e logica:

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

crea widget personalizzati che possono sovrascrivere _renderItemsenza sovrascrivere il _renderItemprototipo di plug-in originale.

nel mio esempio ho anche usato la funzione di rendering originale per semplificare il codice

è importante se si desidera utilizzare il plug-in in luoghi diversi con una vista diversa del completamento automatico e non si desidera violare il codice.


Generalmente è meglio passare il tempo a rispondere a domande più recenti, o a quelle senza risposte piuttosto che a rispondere a una domanda di 6 anni a cui è già stata data una risposta.
zchrykng,

0

Se invece utilizzi il plug-in di terze parti, ha un'opzione di evidenziazione: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(vedi la scheda Opzioni)


sì, sono a conoscenza di questo plug-in. tuttavia, stiamo usando jQueryUI nella nostra app, quindi sarebbe bello farlo funzionare con il plug-in di completamento automatico
jQueryUI

1
Dal 23/06/2010, il plug-in di completamento automatico jQuery è diventato obsoleto a favore del plug-in di completamento automatico dell'interfaccia utente jQuery. Vedere bassistance.de/jquery-plugins/jquery-plugin-autocomplete per ulteriori informazioni
shek

0

Per supportare più valori, basta semplicemente aggiungere la seguente funzione:

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>");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.