オートコンプリートプラグインの結果をカスタムフォーマットするにはどうすればよいですか?


回答:


233

ライブの提案でオートコンプリート

はい、モンキーパッチのオートコンプリートであれば可能です。

jQuery UIのv1.8rc3に含まれるオートコンプリートウィジェットでは、候補のポップアップがオートコンプリートウィジェットの_renderMenu関数で作成されます。この関数は次のように定義されています:

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

_renderItem関数は次のように定義されています。

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

したがって、必要なのは、その_renderItem fnを、目的の効果を生み出す独自の作成に置き換えることです。ライブラリの内部関数を再定義するこの手法は、モンキーパッチと呼ばれています。ここに私がそれをした方法があります:

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

その関数を一度だけ呼び出し$(document).ready(...)ます。

さて、これはハックです:

  • リストにレンダリングされたすべてのアイテムに対して作成されたregexp objがあります。その正規表現オブジェクトはすべてのアイテムで再利用されるべきです。

  • 完成したパーツのフォーマットに使用されるcssクラスはありません。インラインスタイルです。
    つまり、同じページに複数のオートコンプリートがあった場合、それらはすべて同じ扱いになります。CSSスタイルはそれを解決します。

...しかし、それは主要なテクニックを示しており、あなたの基本的な要件に対して機能します。

代替テキスト

更新された作業例:http : //output.jsbin.com/qixaxinuhe


入力された文字の大文字小文字を使用するのではなく、一致文字列の大文字小文字を保持するには、次の行を使用します。

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

言い換えれば、上記の元のコードから始めて、あなただけ交換する必要があるthis.term"$&"


編集
上記は、ページ上のすべてのオートコンプリートウィジェットを変更します。1つだけ変更したい場合は、この質問を参照してください:
ページ上のオートコンプリートの* 1つだけ*のインスタンスにパッチを適用する方法は?


Cheesoに感謝します。このためのjsbinリンクはありますか?
dev.e.loper

1
チェーンを行う場合は、コンテキストをリセットすることが重要です。oldFn.apply(this、[ul、item]);
emanaton

どうもありがとうございました!これがjQuery UIの一部になれば素晴らしいでしょう。
デビッドライダー'07

4
一致する文字列の任意の部分(先頭だけでなく)の結果を太字にしたい場合は、RegExp行を次のように変更します。var re = new RegExp(this.term);
デビッドライダー'07

1
JQueryUIオートコンプリートはデフォルトで大文字と小文字を区別しない検索を行うように見えるため、RegExpオブジェクトに「i」フラグを追加することは理にかなっています。@DavidRyderが述べたように、正規表現で「^」を使用する理由もありません。いいね var re = new RegExp(this.term, "i");
サム

65

これも機能します:

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

@JörnZaeffererと@Cheesoの応答の組み合わせ。


単語全体にマッチするので、私はこの方が好きでした。
ATP

3
これはうまくいきます。注意しなければならないのは、item.labelが置き換えられることだけです。私にとっては、テキストボックスに「<strong ...」と表示されていました。置換結果を別の変数に割り当てるだけで、それは解消されました。データにテキストボックスに入力される値プロパティが含まれている場合は、この問題は発生しません。
Kijana Woodard

複数の値をサポートするオートコンプリートがある場合、これは機能しません。助言がありますか?
leora 2013年

オートコンプリートの結果でテキストを強調表示する最も簡単な方法。上記のleoraとKijanaによって指摘されたバグを明らかに確認してください
adamst85 '20

@RNKushwahaに電話する前にどこでも$().autocomplete()
ブライアンリーシュマン

8

超役立つ。ありがとうございました。+1。

以下は、「文字列は用語で始まる必要がある」に基づいてソートされたライトバージョンです。

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
オロロのおかげで、私は複数の場所でオートコンプリートを使用していて、入力した文字で始まる結果のみを表示するように変更を加えることができる中央の場所を望んでいました。これは私がまさに必要なものです!
dreamerkumar

ありがとう。これはすべての中で最高のソリューションです。大文字と小文字を区別しません。
Aniket Kulkarni 2013

7

ここに、機能的な完全な例があります:

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

お役に立てれば


6

jQueryUI 1.9.0は​​、_renderItemの動作を変更します。

以下のコードは、この変更を考慮に入れており、JörnZaeffererのjQuery Autocompleteプラグインを使用してハイライトマッチングを実行していた方法も示しています。検索語全体の個々の語がすべて強調表示されます。

KnockoutとjqAutoの使用に移行して以来、これは結果をスタイル設定するはるかに簡単な方法であることがわかりました。

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

'('のような文字で検索すると、エラーが発生します( "Uncaught SyntaxError:Invalid regular expression:/(sam | at |()/:Unterminated group")とにかくこれを正規表現との衝突を防ぐことで解決しますか?
Idan

素晴らしい答えです!それがどこに出現するかに関係なく、それが用語を強調するのが好きです。とてもかっこいい。投稿を更新していただきありがとうございます。私が持っていた1つの質問は、使用する.ui-menu-item-highlightクラスについてです。これはjquery-uiまたはコンシューマーによって定義されると予想されますか?クラス名を独自の手段に変更し、font-weightを太字にしました。 .jqAutocompleteMatch { font-weight: bold; }
Sam

@IdanShechter素晴らしいコメント。this.termfor regex をエスケープするロジックは、処理を行う前に使用する必要があります。これを行う方法に対する多くの回答の1つとして、JavaScript正規表現で使用するエスケープ文字列を参照してください。
Sam

3

さらに簡単な方法として、これを試してください:

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

これがTed de Koningのソリューションのリハッシュです。以下が含まれます:

  • 大文字と小文字を区別しない検索
  • 検索された文字列の多くの出現を見つける
$.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
あなたは車輪を再発明していると思います!このすべてのコードよりも速く、簡単で、コンパクトな正規表現を使用してみませんか?
George Mavritsakis

2

これは、正規表現を必要とせず、ラベルの複数の結果に一致するバージョンです。

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

これはおそらく最良の解決策ですが、string.splitは大文字と小文字を区別する一致のみが可能だと思います。
Noel Abrahams、2011

大文字と小文字を区別しない単語に基づいて単語を照合する方法はありますか?「アルファ」を検索しても「アルファ」はハイライト表示されないため
Patrick


1

これが私のバージョンです:

  • RegExの代わりにDOM関数を使用して文字列を分割/スパンタグを挿入
  • すべてではなく、指定されたオートコンプリートのみが影響を受けます
  • UIバージョン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);
};

一致したテキストの例を強調表示


1

次のコードを使用できます。

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

とロジック:

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

オリジナルのプラグインプロトタイプ_renderItemを上書きせずにオーバーライドできるカスタムウィジェットを作成します_renderItem

私の例では、元のレンダリング関数を使用してコードを単純化しました

オートコンプリートのビューが異なるさまざまな場所でプラグインを使用し、コードを壊したくない場合は重要です。


一般に、すでに回答済みの6歳の質問に回答するよりも、新しい質問または回答のない質問に回答することに時間を費やす方がよいでしょう。
zchrykng 2016年

0

代わりにサードパーティのプラグインを使用する場合、ハイライトオプションがあります:http : //docs.jquery.com/Plugins/Autocomplete/autocomplete#url_or_dataoptions

(「オプション」タブを参照)


ええ、私はこのプラグインを知っています。ただし、私たちはアプリでjQueryUIを使用しているので、jQueryUI Autocompleteプラグインでこれを機能させるとよいでしょう
dev.e.loper

1
2010-06-23現在、jQuery AutocompleteプラグインはjQuery UI Autocompleteプラグインを支持して廃止されました。参照してくださいbassistance.de/jquery-plugins/jquery-plugin-autocomplete詳細について
蒋介石

0

複数の値をサポートするには、次の関数を追加するだけです。

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>");
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.