wake-up-neo.com

jQuery UI Autocomplete deaktivieren Ereignisse auswählen und schließen

Ich verwende die Autocomplete-Funktion der jQuery-Benutzeroberfläche etwas anders, als sie wahrscheinlich erstellt wurde.

Grundsätzlich möchte ich alle die gleiche Funktionalität beibehalten. Der einzige Unterschied besteht darin, dass beim Anzeigen des Vorschlagsfelds das Vorschlagsfeld nicht ausgeblendet wird, wenn ein Benutzer eine Auswahl trifft, und ich möchte auch nicht, dass diese Auswahl das Eingabefeld auffüllt dass .autocomplete mit verbunden ist.

Ich habe also die jQuery-UI-Dokumentation durchgelesen, und es scheint, dass es eine Möglichkeit gibt, die Ereignisse Select: und Close: zu deaktivieren, aber ich finde die Art, wie sie es erklärt haben, sehr verwirrend und daher auch ich Ich bitte um Hilfe.

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

Offizielle jQuery UI-Dokumentation

Wird ausgelöst, wenn ein Menüpunkt ausgewählt wird. ui.item bezieht sich auf das ausgewählte Element. Die Standardaktion von select besteht darin, den Wert des Textfelds durch den Wert des ausgewählten Elements zu ersetzen. Wenn Sie dieses Ereignis abbrechen, wird der Wert nicht aktualisiert, aber Verhindert nicht, dass das Menü geschlossen wird.

Codebeispiele

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

Verwechslung

Was mich verwirrt, ist, dass sie den Anschein haben, ".autocomplete" zu entfernen und durch .bind ("autocompleteselect") zu ersetzen - wodurch die Autocomplete-Funktion vollständig deaktiviert wird.

Vielen Dank für jede Hilfe, die Sie geben können.

16
thathurtabit

Die zweite Syntax mit .bind() ist einfach eine weitere Möglichkeit, einen Event-Handler an die benutzerdefinierten Ereignisse von jQueryUI anzuhängen. Dies ist genau das gleiche wie das Definieren des Ereignishandlers in den Widgetoptionen (mithilfe von select: function(event, ui) { }).

Stellen Sie sich vor, Sie hätten mehrere Widgets zur automatischen Vervollständigung auf der Seite und Sie wollten die gleiche Funktion ausführen, wenn einer von ihnen das "select" -Ereignis ausgelöst hat, zum Beispiel:

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

Wenn Sie das Ereignis select abbrechen, haben Sie dies richtig. Das Abbrechen des close-Ereignisses ist jedoch etwas schwieriger. Es scheint, dass die Rückgabe von false vom Event-Handler nicht funktioniert (close wird ausgelöst, nachdem das Menü tatsächlich geschlossen wurde). Sie könnten einen kleinen Hacker ausführen und einfach die Funktion select durch Ihre eigene ersetzen:

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

Hier ist ein funktionierendes Beispiel dafür: http://jsfiddle.net/ZGmyp/

Ich bin nicht sicher, welche Folgen es hat, das nahe Ereignis zu überschreiben, aber es sieht nicht so aus, als ob in dem einfachen Beispiel etwas Verrücktes passiert. Ich würde sagen, dass dies eine Art unnatürliche Verwendung des Widgets ist, so dass unerwartete Konsequenzen auftreten können.

12
Andrew Whitaker

Als ich mich von der Lösung von Andrews inspirieren ließ, fand ich einen Weg, die Autovervollständigung bei der Auswahl offen zu halten, ohne die Kernfunktionen zu beeinträchtigen:

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

Die Idee ist also, die Methode close close zu neutralisieren, wie durch das ausgewählte Flag angegeben. Flag im globalen Namensraum zu wählen, ist wahrscheinlich nicht die beste Idee, aber das kann jemand anderes verbessern :-).

Mehr über überschreibende Methoden

19
corolla

Ich habe die verschiedenen Ideen ausprobiert, die andere hier ohne Erfolg präsentiert haben.

Ich benutze Jquery 2.1.4 mit UI 1.11.4 und so habe ich das zum Laufen gebracht:

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>

Backend-Quelle "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;

?>
2
Drew

Ich bin einen etwas anderen Weg gegangen und habe Andrews Geige erweitert.

Der Zweck war, dass ich immer wollte, dass die automatische Vervollständigung angezeigt wird, während eine bestimmte Eingabe den Fokus hatte - so dass mehrere Auswahlmöglichkeiten möglich waren.

$("#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

Mit $ input.data ("autocomplete"). Menu.options.selected = function () {} Führte dazu, dass der Wert nach Auswahl eines anderen Elements nicht hielt (unsere Implementierung musste an das Ende angehängt werden. Möglicherweise nur erforderlich Fügen Sie e.preventDefault () hinzu oder geben Sie vor dem Anfügen von Code false zurück. Also habe ich gerade beim close-Ereignis umgestellt. Beispiel mit dem Setzen externer Variablen und dem Schreiben eigener Methoden ist besser, hat mir aber auch nicht gefallen. Ich rufe zuerst die Methode manuell mit dem Übergeben eines Parameters auf, wenn Autocomplte von Hand geschlossen werden muss. (In unserer Implementierung forderte der Kunde, dass die Liste beim Klicken auf die Elemente geöffnet ist, aber geschlossen wird, wenn die Maus den Textbox-Container verlässt. 

Also habe ich Autocomplete einfach an den Elementcontainer der Textbox angehängt und Mouseenter und Mouseleave angehängt. Um festzustellen, ob es geschlossen werden soll, habe ich die benutzerdefinierte Variable jQuery (this) .data ("canClose") verwendet. Im Wesentlichen wird die automatische Vervollständigung mit der Suchmethode wieder geöffnet, wenn die Variable "false" ist.

Hier ist der endgültige Code:

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

wenn Sie das Anfügen statt Ersetzen durchführen müssen, fügen Sie den Select-Handler im Konstruktor hinzu:

 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