首页 > 解决方案 > jquery multiple custom combobox with custom -renderItem causes cross event fire

问题描述

I have a question that I have been unable to resolve. On a data entry screen I have 4 jquery-ui custom comboboxes. I had them working fine even though they each have a thousand or so options. One of them I wanted to be able to display multi-line options. I found a few examples of creating a custom _renderItem extension on the autocomplete to do this. Problem is when I have a custom _renderItem, and I click on an item in any of the custom comboboxes, the click events for ALL FOUR comboboxes will fire. If I don't have the custom _renderItem, then everything works fine and only the event for clicked combobox fires. The alert in "this._on( this.input" tells me which event (or events) fired.

After .autocomplete({ you will see the various methods I have attempted. I even tried just the default renderitem function without modifying the label or value, and it still gave me the crossfire events.

I SUSPECT that data("autocomplete") is assigning based on the classname, and custom combobox is creating 4 ul's with that classname, but I don't know how to pick the particular ul.

Any suggestions would be greatly appreciated.

Thanks in advance!

I am using jquery-1.12.4.js and ui/1.12.1/jquery-ui.js


      /* create custom typeahead combobox */
      $.widget( "custom.combobox", {
        _create: function() {
          this.wrapper = $( "<span>" )
            .addClass( "custom-combobox" )
            .insertAfter( this.element );
    
          var obj = this.element.get(0);  /* select object */
          var objid = obj.id;
          
          this._createULHolder(objid),  
          this._createInner();
          this.element.hide();
          this._createAutocomplete(objid);
          this._createShowAllButton();
        },
    
        _createULHolder:function(objid) {
          var theBody = document.getElementsByTagName('body')[0];
          this.ulholder = $("<div>")
            .appendTo(theBody)
            .addClass("ui-input-text ui-body-inherit ui-shadow-inset " + 'divul_' + objid)
            .attr('id','divul_' + objid)
            .attr('style','position:absolute;left:-999em')
        },
    
        _createInner:function() {
          this.inner = $("<div>")
            .appendTo(this.wrapper)
            .addClass("ui-input-text ui-body-inherit ui-shadow-inset custom-combobox-input-wrapper")  /* my-ui-no-margin */
    
        },
    
        _createAutocomplete: function(objid) {
          var selected = this.element.children( ":selected" ),
            value = selected.val() ? selected.text() : "";
            if (value.indexOf('|') > -1) {
              var lines = value.split('|');
              value = lines[0];
            }
    
          this.input = $( "<input>" )
            .appendTo( this.inner )
            .val( value )
            .attr( "title", "" )
            .attr( "id", "combobox_" + objid)
            .addClass( "custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left" )
              .tooltip({
              classes: {
                "ui-tooltip": "ui-state-highlight"
              }
            })
            .autocomplete({
              delay: 0,
              minLength: 0,
              appendTo:"#divul_" + objid,
              classes: { "ui-autocomplete": "ui-autocomplete-" + objid },
              source: $.proxy( this, "_source" )
            });
    
    /*        this.input                                    
            .autocomplete("ui-autocomplete-" + objid)._renderItem = function( ul, item ) {
              return $( "<li>" )
                .append( "<div>" + item.label + "<br>" + item.desc + "</div>" )
                .appendTo( ul );
            };*/
    /*          .data("ui-autocomplete")._renderItem = function (ul, item) {
                var tlabel = item.label;
                if (tlabel.indexOf('|') > -1) {
                  var lines = tlabel.split('|');
                  tlabel = '<span class="ui-selectmenu-menu-item-header">' + lines[0].trim() + ' </span>';
                  for (var i = 1; i < lines.length; i++) {
                    tlabel = tlabel + '<span class="ui-selectmenu-menu-item-lines"> - ' + lines[i].trim() + '</span>';
                  }
                }
    
                var d = $("<div></div>")
                    .data("item.autocomplete", item)
                    .append(item.label);
             return $("<li>")
                 .attr("data-value",item.value)
                 .append(d)
                 .appendTo(ul);
            };*/
    
          this._on( this.input, {
            autocompleteselect: function( event, ui ) {
              ui.item.option.selected = true;
              this._trigger( "select", event, {
                item: ui.item.option
              });
    
              tlabel = ui.item.option.label;
              if (tlabel.indexOf('|') > -1) {
                var lines = tlabel.split('|');
                tlabel = lines[0];
                $("#combobox_" + objid).val(tlabel);
              }
                alert('objid=' + objid + ' val=' + $("#combobox_" + objid).val() + ' tlabel=' + tlabel);
    
            },
    
            autocompletechange: "_removeIfInvalid"
          });
        },
    
        _createShowAllButton: function() {
          var input = this.input,
            wasOpen = false;
    
          $( "<a>" )
            .attr( "tabIndex", -1 )
            .attr( "title", "Show All Items" )
            .tooltip()
            .appendTo( this.wrapper )
            .button({
              icons: {
                primary: "ui-icon-triangle-1-s"
              },
              text: false
            })
            .removeClass( "ui-corner-all" )
            .addClass( "custom-combobox-toggle ui-corner-right" )
            .on( "mousedown", function() {
              wasOpen = input.autocomplete( "widget" ).is( ":visible" );
            })
            .on( "click", function() {
              input.trigger( "focus" );
    
              // Close if already visible
              if ( wasOpen ) {
                return;
              }
    
              // Pass empty string as value to search for, displaying all results
              input.autocomplete( "search", "" );
            });
        },
    
       _source: function( request, response ) {
    
        var matcher = new RegExp( $.ui.autocomplete.escapeRegex(request.term), "i" );
        var select_el = this.element.get(0); // get dom element
        var rep = new Array(); // response array
    
        // simple loop for the options
        for (var i = 0; i < select_el.options.length; i++) {
            var text = select_el.options[i].text;
    
            if ( select_el.options[i].value && ( !request.term || matcher.test(text) ) )
                // add element to result array
                rep.push({
                    label: text, // no more bold
                    value: text,
                    option: select_el.options[i]
                });
        }
        // send response
        response( rep );
    },
        _removeIfInvalid: function( event, ui ) {
    
          // Selected an item, nothing to do
          if ( ui.item ) {
            return;
          }
    
          // Search for a match (case-insensitive)
          var value = this.input.val(),
            valueLowerCase = value.toLowerCase(),
            valid = false;
          this.element.children( "option" ).each(function() {
            if ( $( this ).text().toLowerCase() === valueLowerCase ) {
              this.selected = valid = true;
              return false;
            }
          });
    
          // Found a match, nothing to do
          if ( valid ) {
            return;
          }
    
          // Remove invalid value
          this.input
            .val( "" )
            .attr( "title", value + " didn't match any item" )
            .tooltip( "open" );
          this.element.val( "" );
          this._delay(function() {
            this.input.tooltip( "close" ).attr( "title", "" );
          }, 2500 );
          this.input.autocomplete( "instance" ).term = "";
        },
    
        _destroy: function() {
          this.wrapper.remove();
          this.element.show();
        }
      });
    
    
      $( function() {
          $("#dd1").combobox(); 
    
          $("#dd2").combobox(); 
          $("#dd3").combobox(); 
          $("#dd4").combobox(); 
      });

标签: javascriptjquerycombobox

解决方案


推荐阅读