Como formatar de forma personalizada os resultados do plug-in de preenchimento automático?


Respostas:


233

Preenchimento automático com sugestão ao vivo

Sim, você pode, se fizer o patch automático do macaco.

No widget de preenchimento automático incluído na v1.8rc3 da interface do usuário do jQuery, o pop-up de sugestões é criado na função _renderMenu do widget de preenchimento automático. Esta função é definida assim:

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

A função _renderItem é definida assim:

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

Portanto, o que você precisa fazer é substituir o _renderItem fn pela sua própria criação que produz o efeito desejado. Essa técnica, redefinindo uma função interna de uma biblioteca, aprendi a chamar -se patch de macaco . Aqui está como eu fiz isso:

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

Chame essa função uma vez $(document).ready(...).

Agora, isso é um hack, porque:

  • há um objeto regexp criado para cada item renderizado na lista. Esse objeto regexp deve ser reutilizado para todos os itens.

  • não há classe css usada para a formatação da peça concluída. É um estilo embutido.
    Isso significa que, se você tivesse vários preenchimentos automáticos na mesma página, todos receberiam o mesmo tratamento. Um estilo css resolveria isso.

... mas ilustra a técnica principal e funciona para seus requisitos básicos.

texto alternativo

exemplo de trabalho atualizado: http://output.jsbin.com/qixaxinuhe


Para preservar o caso das cadeias de correspondência, em vez de usar o caso dos caracteres digitados, use esta linha:

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

Em outras palavras, a partir do código original acima, basta substituir this.termpor "$&".


EDITAR
O texto acima altera todos os widgets de preenchimento automático na página. Se você deseja alterar apenas uma, consulte esta pergunta:
Como corrigir * apenas uma * instância do preenchimento automático em uma página?


Obrigado Cheeso. Você tem o link jsbin para isso?
dev.e.loper

1
Observe que, se você encadear as coisas, é importante redefinir o contexto: oldFn.apply (this, [ul, item]);
emanaton

Muito obrigado! Seria incrível se isso se tornasse parte da UI do jQuery.
David Ryder

4
Uma coisa que eu diria é que, se você deseja que o resultado seja negrito em qualquer parte da string correspondente (não apenas no começo), modifique a linha RegExp para isso: var re = new RegExp (this.term);
David Ryder

1
O preenchimento automático do JQueryUI parece fazer uma pesquisa sem distinção entre maiúsculas e minúsculas por padrão; portanto, faz sentido adicionar o sinalizador "i" no objeto RegExp. Também não há razão para usar o "^" no regex como o @DavidRyder mencionado. Como: var re = new RegExp(this.term, "i"); Ótimo post!
Sam

65

isso também funciona:

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

uma combinação das respostas de @ Jörn Zaefferer e @ Cheeso.


Gostei mais deste, pois combina com a palavra toda.
atp

3
Isso funciona bem. A única coisa a se observar é que o item.label está sendo substituído. Para mim, eu estava ficando "<forte ..." na minha caixa de texto. Apenas atribuir o resultado da substituição a outra variável esclareceu isso. Você não teria esse problema se seus dados contiverem uma propriedade value que é colocada na caixa de texto.
Kijana Woodard

isso não funciona se você tiver um preenchimento automático compatível com vários valores. alguma sugestão?
Leora

A maneira mais simples de destacar o texto nos resultados do preenchimento automático. Obviamente olhar para os erros como apontado por Leora e Kijana acima
adamst85

@RNKushwaha qualquer lugar antes de chamar a$().autocomplete()
Brian Leishman

8

Super útil. Obrigado. +1.

Aqui está uma versão light que classifica "String deve começar com o termo":

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
Obrigado Orolo, eu estava usando o preenchimento automático em vários locais e queria um local central onde eu possa fazer a alteração para mostrar apenas o resultado que começa com os caracteres digitados e esse é exatamente o que eu precisava!
precisa saber é o seguinte

Obrigado. Esta é a melhor solução de todas. Funciona para maiúsculas e minúsculas.
Aniket Kulkarni

7

Aqui está, um exemplo completo funcional:

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

Espero que isto ajude


6

O jQueryUI 1.9.0 altera como o _renderItem funciona.

O código abaixo leva essa alteração em consideração e também mostra como eu estava realizando a correspondência de destaque usando o plug-in de preenchimento automático do jQuery de Jörn Zaefferer. Ele destacará todos os termos individuais no termo geral da pesquisa.

Desde que passei a usar o Knockout e o jqAuto, achei uma maneira muito mais fácil de estilizar os resultados.

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 eu procuro caracteres como '(', isso causa um erro ("Untaught SyntaxError: Expressão regular inválida: / (sam | at | () /: grupo não terminado")) de qualquer maneira para resolver isso, impedindo a colisão com regex?
Idan Shechter

Resposta incrível! Adoro o fato de destacar os termos, independentemente de onde eles apareçam. Muito legal. Obrigado por atualizar a postagem. Uma pergunta que tive foi sobre a classe .ui-menu-item-realce que você usa. Isso deve ser definido pelo jquery-ui ou pelos consumidores? Mudei o nome da classe para combinar com meus próprios meios e simplesmente tornei o peso da fonte em negrito. .jqAutocompleteMatch { font-weight: bold; }
Sam

@IdanShechter Ótimo comentário. Alguma lógica para escapar do this.termregex for deve ser usada antes de qualquer processamento. Consulte String de escape para uso em regex Javascript como uma das muitas respostas sobre como fazer isso.
Sam

3

para uma maneira ainda mais fácil, tente o seguinte:

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

Aqui está uma nova versão da solução de Ted de Koning. Inclui :

  • Pesquisa sem distinção entre maiúsculas e minúsculas
  • Localizando muitas ocorrências da sequência pesquisada
$.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
Eu acho que você está reinventando a roda! Por que você não usa expressões regulares que são mais rápidas, mais fáceis e mais compactas que todo esse código?
George Mavritsakis

2

Aqui está uma versão que não requer expressões regulares e corresponde a vários resultados no rótulo.

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

Esta é provavelmente a melhor solução, mas o string.split é capaz de apenas correspondências que diferenciam maiúsculas de minúsculas, acredito.
Noel Abrahams

Você tem alguma maneira de combinar palavras com base em não diferencia maiúsculas de minúsculas? Porque se eu tiver uma pesquisa "alfa", não irá destacar "Alfa"
Patrick


1

Aqui está a minha versão:

  • Usa funções DOM em vez de RegEx para quebrar cadeias / injetar tags de extensão
  • Somente o preenchimento automático especificado é afetado, nem todos
  • Funciona com a interface do usuário versão 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);
};

Destaque exemplo de texto correspondente


1

você pode usar o seguinte código:

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 lógica:

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

ele cria um widget personalizado que pode substituir _renderItemsem substituir_renderItem protótipo do plug-in original.

no meu exemplo também usou a função de renderização original para simplificar o código

é importante se você deseja usar o plug-in em locais diferentes, com diferentes visões do preenchimento automático e não deseja quebrar seu código.


Geralmente, é melhor dedicar tempo a responder perguntas mais recentes ou sem respostas, em vez de responder a uma pergunta de 6 anos que já foi respondida.
Zchrykng 16/05

0

Se você usar o plug-in de terceiros, ele terá uma opção de destaque: http://docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(consulte a guia Opções)


sim, eu estou ciente deste plug-in no entanto, estamos usando jQueryUI em nosso aplicativo de modo que seria bom para começar este trabalho com jQueryUI Autocomplete plug-in.
dev.e.loper

1
Desde 23/06/2010, o plug-in de preenchimento automático do jQuery foi descontinuado em favor do plug-in de preenchimento automático da interface do usuário do jQuery. Veja bassistance.de/jquery-plugins/jquery-plugin-autocomplete para obter mais informações
shek

0

Para suportar vários valores, basta adicionar a seguinte função:

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>");
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.