web-dev-qa-db-ja.com

jQuery UIのオートコンプリートによるSelect&Closeイベントの無効化

私は、jQuery UIのオートコンプリートを、おそらく作成のために作成されたものとは少し異なる方法で使用しています。

基本的にはすべて同じ機能を維持したいのですが、唯一の違いは、提案ボックスが表示されたときに、ユーザーが選択を行ったときに提案ボックスが非表示にならず、その選択が入力ボックスに表示されないようにすることです。 .autocompleteが添付されています。

だから、私はjQuery UIのドキュメントを読んでいて、Select:とClose:イベントを無効にする方法があるようですが、彼らがそれを説明している方法は非常にわかりにくいので、これが理由ですここに助けを求めています。

My jQuery

$( "#comment" ).autocomplete({
    source: "comments.php",
    minLength: 4,

    // Attempt to remove click/select functionality - may be a better way to do this        
    select: function( event, ui ) {
        return false;
    },
    // Attempt to add custom Class to the open Suggestion box - may be a better way
    open : function (event, ui) {
        $(this).addClass("suggestion-box");
    },
    // Attempt to cancel the Close event, so when someone makes a selection, the box does not close
    close : function (event, ui) {
        return false;   
    }
});

公式のjQuery UIドキュメント

メニューからアイテムが選択されるとトリガーされます。 ui.itemは、選択されたアイテムを参照します。 selectのデフォルトのアクションは、テキストフィールドの値を選択されたアイテムの値で置き換えることです。このイベントをキャンセルすると、値が更新されなくなりますが、メニューを閉じることはできます。

コード例

Supply a callback function to handle the select event as an init option.
$( ".selector" ).autocomplete({
   select: function(event, ui) { ... }
});
Bind to the select event by type: autocompleteselect.
$( ".selector" ).bind( "autocompleteselect", function(event, ui) {
  ...
});

混乱

私を混乱させるのは、.autocompleteを削除して.bind( "autocompleteselect")で置き換えるよう提案しているように見えることです。これにより、オートコンプリートが完全に無効になりますか?

あなたが与えることができるあらゆる助けを本当にありがとう。

17
thathurtabit

.bind()を使用する2番目の構文は、jQueryUIのカスタムイベントにイベントハンドラーをアタッチするもう1つの方法です。これは、ウィジェットオプション内でイベントハンドラーを定義することとまったく同じです(select: function(event, ui) { }を使用)。

たとえば、ページにいくつかのオートコンプリートウィジェットがあり、それらのいずれかが「select」イベントを発生させたときに同じ関数を実行したいとします。

$(".autocomplete").bind("autocompleteselect", function(event, ui) {
    /* Will occur when any element with an autocomplete widget fires the
     * autocomplete select event.
     */
});

selectイベントをキャンセルすることに関しては、あなたは正しいです。ただし、closeイベントのキャンセルは少し難しいです。イベントハンドラーからfalseを返すと機能しないようです(closeは、メニューが実際に閉じられた後に発生します)。小さなハッカーを実行して、select関数を自分の関数に置き換えるだけです。

var $input = $("input").autocomplete({
    source: ['Hello', 'Goodbye', 'Foo', 'Bar']
});
$input.data("autocomplete").menu.options.selected = function(event, ui) { 
    var item = ui.item.data( "item.autocomplete" );
    $input.focus();
};

以下はその動作例です: http://jsfiddle.net/ZGmyp/

Closeイベントをオーバーライドすることの影響はわかりませんが、単純な例でクレイジーなことが起こっているようには見えません。これはウィジェットの不自然な使い方の一種であるため、予期しない結果が生じる可能性があります。

12
Andrew Whitaker

Andrewsソリューションからインスピレーションを得て、コア機能への影響を少なくして、選択時にオートコンプリートを開いたままにする方法を見つけました。

var selected;  //flag indicating a selection has taken place

var $input = $("input").autocomplete({
    source: ['Hello', 'Goodbye', 'Foo', 'Bar'],
    select: function( event, ui ) {
        selected = true;
    }
});

//Override close method - see link below for details
(function(){
   var originalCloseMethod = $input.data("autocomplete").close;
    $input.data("autocomplete").close = function(event) {
        if (!selected){
            //close requested by someone else, let it pass
            originalCloseMethod.apply( this, arguments );
        }
        selected = false;
    };
})();

そのため、選択されたフラグで示されるように、適切な場合はメソッドを無効にすることがアイデアです。グローバル名前空間でフラグを選択することはおそらく最良のアイデアではありませんが、それは誰かが:-)を改善するためのものです。

オーバーライドメソッドの詳細

21
corolla

他の人が提示したさまざまなアイデアを試しましたが、成功しませんでした。

私はUI 1.11.4でJquery 2.1.4を使用していますが、これは私がこれを機能させる方法です:

Javascript:


<script>
var lookup_selectable = false;
var lookup_term = '';

$(function() {

    $( "#lookup" ).autocomplete({
        source: "lookup_processor.php",
        minLength: 3,
        renderItem: function( ul, item ) {

            // This function is called for each item returned from the 'source:'
            // It is up to you to ensure that a list item element is returned.

            // do whatever logic on the item data to determine if it should not be slectable..


            //Example:
            // The backend "source" has handled the logic of what is selectable or not
            // and has set a 'selectable' parameter that we can use
            if(item.selectable){                  
                // return the item unchanged from autocompletes default behavior
                return $("<li></li>").data("item.autocomplete", item).append("<a>" + item.label + "</a>").appendTo(ul);              
            }else{
                // this item is not selectable so lets apply a class named 'item-disabled' to give a visual queue. 
                // We are also wrapping the label in a span instead of an anchor just to show that the item is still clickable,  darn!
                return $('<li class="ui-menu-item item-disabled"></li>').data("item.autocomplete", item).append('<span>'+item.label+'</span>').appendTo(ul);                  
            }

        },

        select: function( event, ui ) {                                  

            // This item was clicked ..

            // save the item.clickable value to our own external variable
            // Note: We have to do this because the item object is not available in the 'close' function :-(
            lookup_selectable = ui.item.selectable;  // the item object is available inside the ui parameter

            // store the current search term
            lookup_term = $('#lookup').val();

            // do any additional stuff based on the item selected, if needed...


        },

        close: function(event, ui){

            // This function fires after select: and after autocomplete has already "closed" everything.  This is why event.preventDefault() won't work.               
            // ** ui is an empty object here so we have to use our own variable to check if the selected item is "selectable" or not..                              
            if (! lookup_selectable){
                // We need to undo what autocomplete has already done..                                                       
                $('#lookup').val(lookup_term); // Restore the search term value
                $('#'+event.currentTarget.id).show(); // Keep the selection window open
                // ta-da!  To the end user, nothing changes when clicking on an item that was not selectable.
            }    
        }

    });
});
</script>  

CSS:


<style>
li.ui-menu-item.item-disabled {
    text-decoration: none;    
    line-height: 1.5;    
    color: #ccc;
}
</style>

バックエンドソース "lookup_processor.php":


<?php

        $search_results = array();

    // ..do whatever to get the data for each item
    $item_data = getting_item_data();

    foreach ($item_data as $data){
        // The id, label, and value keys are the typical keys that autocomplete expects,  but you can add ass many others as you want..
        // For our example we are setting the 'selectable' key to true or false based on some simple example logic
        $search_results[] = array(
            'id'=>$data['id'], 
            'label'=>$data['label'], 
            'value'=>$data['value'], 
            'selectable'=>$data['some_thing_to_check']>0?true:false, // This is the parameter our 'select:' function is looking for
            'send_it_all_if_you_want'=>json_encode($data)); // this is just an example of how you can send back anything you want 
         );
     }

    // send the results back to autocomplete
    echo json_encode($search_results);
    exit;

?>
4
Drew

私はこれのために少し異なるルートをたどり、Andrewの fiddle を拡張しました

目的は、特定の入力がフォーカスされている間、オートコンプリートが常に表示されるようにしたかったためです-複数の選択が可能です。

$("#myInput").autocomplete({
    source: ["Test", "This", "Doesnt", "Close"],
    minLength: 0,
    select: function (event, ui) {
        // Add your own custom login to manipulate ui.item.label and add what you need the input field (and ui.item.value if required.)
        // We've customised how we want the select to "work" so prevent the default
        // of auto clearing the input.    
        event.preventDefault();
    },
    close : function(event)
    {
        // We're closing the autocomplete - check if the input still has focus...
        if ($("#myInput").is(":focus"))
        {
            // Prevent the auto complete from closing.
            event.preventDefault();

            // Make sure we're reshowing the autcomplete - since the input would have momentarily
            // lost focus when we selected an item.
            $("#myInput").autocomplete("search", "")
        }        
    }
});

$("#myInput").focus(function () {
    // We're not taking any filtering into account for this example.
    $(this).autocomplete("search", "")
});
1
Davie Brown

$ input.data( "autocomplete")。menu.options.selected = function(){}を使用すると、別の項目を選択した後に値が保持されませんでした(最後に追加する必要のある実装です。おそらくe.preventDefault( )または、追加コードの前にfalseを返します)。そのため、クローズイベントで切り替えを行いました。外部変数を入れて独自のメソッドを書く例はより良いですが、それも好きではありませんでした。最初に、手動でオートコンパイルを閉じる必要があるときに、パラメーターを渡して手動でメソッドを呼び出す方法を説明します。 (私たちの実装では、項目をクリックするときにリストを開く必要があり、マウスがテキストボックスコンテナーから離れるとリストを閉じる必要がありました。

したがって、テキストボックスの要素コンテナにオートコンプリートをアタッチし、mouseenterとmouseleaveをアタッチしました。閉じる必要があるかどうかを判断するために、jQuery(this).data( "canClose")カスタム変数を使用しました。基本的に、それが行うことは、変数が「false」の場合に検索メソッドでオートコンプリートを再び開くことです。

これが最終的なコードです:

element.autocomplete({
                minLength:0,
                source: source,
                appendTo: element.parent(),
                close: function () {
                    if (!jQuery(this).data("canClose")) {
                        jQuery(this).autocomplete('search', '');
                    }
                    return false;
                }
            });
            element.mouseenter(function () {
                element.data("canClose", false);
                jQuery(this).autocomplete('search', '');
            });
            element.parent().mouseleave(function () {
                element.data("canClose", true);
                element.delay(2000).autocomplete("close");
            });

値を置き換えるのではなく追加を行う必要がある場合は、コンストラクターに選択ハンドラーを追加します。

 select: function (event, ui) {
                    var text = element.text().trim();
                    if (text.length > 0 && !text.endsWith(",")) {
                        text += ", ";
                    }
                    jQuery(this).text((text + ui.item.label));
                    jQuery(this).focus();
                    return false;
                }
0
Andrey Doloka