文本字段和下拉组合框

问题描述:

我是JavaScript新手,我试图添加一个组合框到我创建的窗体中,我希望用户能够输入答案或从下拉列表中选择一个。我在网上找到了一个插件并进行了设置。下拉菜单可以正常工作,但用户输入的答案不会保存在文本字段中,当您单击不在其消失的文本框时。文本字段和下拉组合框

我看着代码的onblur部分,看看我是否可以改变行为,但我不能。有人可以帮忙吗?代码如下。

我的HTML(我使用的引导)

<div class="col-md-4"> 
     <div class="form-group"> 
          <div class="input-group"> 
           <label for="user_id" class="input-group-addon">User ID</label> 
           <select class="combobox input-large form-control" name="user_id" id="user_id"> 
           <option value="" selected="selected">Enter ID</option> 
           <option value="ML">Multiple Users</option> 
           <option value="UN">Unknow User</option> 
           </select> 
          </div> 
         </div> 
    </div> 

和JavaScript

!function($) { 

"use strict"; 

/* COMBOBOX PUBLIC CLASS DEFINITION 
    * ================================ */ 

    var Combobox = function (element, options) { 
    this.options = $.extend({}, $.fn.combobox.defaults, options); 
    this.template = this.options.template || this.template 
    this.$source = $(element); 
    this.$container = this.setup(); 
    this.$element = this.$container.find('input[type=text]'); 
    this.$target = this.$container.find('input[type=hidden]'); 
    this.$button = this.$container.find('.dropdown-toggle'); 
    this.$menu = $(this.options.menu).appendTo('body'); 
    this.matcher = this.options.matcher || this.matcher; 
    this.sorter = this.options.sorter || this.sorter; 
    this.highlighter = this.options.highlighter || this.highlighter; 
    this.shown = false; 
    this.selected = false; 
    this.refresh(); 
    this.transferAttributes(); 
    this.listen(); 
    }; 

    Combobox.prototype = { 

    constructor: Combobox 

    , setup: function() { 
     var combobox = $(this.template()); 
     this.$source.before(combobox); 
     this.$source.hide(); 
     return combobox; 
    } 

    , disable: function() { 
     this.$element.prop('disabled', true); 
     this.$button.attr('disabled', true); 
     this.disabled = true; 
     this.$container.addClass('combobox-disabled'); 
    } 

    , enable: function() { 
     this.$element.prop('disabled', false); 
     this.$button.attr('disabled', false); 
     this.disabled = false; 
     this.$container.removeClass('combobox-disabled'); 
    } 
    , parse: function() { 
     var that = this 
     , map = {} 
     , source = [] 
     , selected = false 
     , selectedValue = ''; 
     this.$source.find('option').each(function() { 
     var option = $(this); 
     if (option.val() === '') { 
      that.options.placeholder = option.text(); 
      return; 
     } 
     map[option.text()] = option.val(); 
     source.push(option.text()); 
     if (option.prop('selected')) { 
      selected = option.text(); 
      selectedValue = option.val(); 
     } 
     }) 
     this.map = map; 
     if (selected) { 
     this.$element.val(selected); 
     this.$target.val(selectedValue); 
     this.$container.addClass('combobox-selected'); 
     this.selected = true; 
     } 
     return source; 
    } 

    , transferAttributes: function() { 
    this.options.placeholder = this.$source.attr('data-placeholder') || this.options.placeholder 
    this.$element.attr('placeholder', this.options.placeholder) 
    this.$target.prop('name', this.$source.prop('name')) 
    this.$target.val(this.$source.val()) 
    this.$source.removeAttr('name') // Remove from source otherwise form will pass parameter twice. 
    this.$element.attr('required', this.$source.attr('required')) 
    this.$element.attr('rel', this.$source.attr('rel')) 
    this.$element.attr('title', this.$source.attr('title')) 
    this.$element.attr('class', this.$source.attr('class')) 
    this.$element.attr('tabindex', this.$source.attr('tabindex')) 
    this.$source.removeAttr('tabindex') 
    if (this.$source.attr('disabled')!==undefined) 
     this.disable(); 
    } 

    , select: function() { 
     var val = this.$menu.find('.active').attr('data-value'); 
     this.$element.val(this.updater(val)).trigger('change'); 
     this.$target.val(this.map[val]).trigger('change'); 
     this.$source.val(this.map[val]).trigger('change'); 
     this.$container.addClass('combobox-selected'); 
     this.selected = true; 
     return this.hide(); 
    } 

    , updater: function (item) { 
     return item; 
    } 

    , show: function() { 
     var pos = $.extend({}, this.$element.position(), { 
     height: this.$element[0].offsetHeight 
     }); 

     this.$menu 
     .insertAfter(this.$element) 
     .css({ 
      top: pos.top + pos.height 
     , left: pos.left 
     }) 
     .show(); 

     $('.dropdown-menu').on('mousedown', $.proxy(this.scrollSafety, this)); 

     this.shown = true; 
     return this; 
    } 

    , hide: function() { 
     this.$menu.hide(); 
     $('.dropdown-menu').off('mousedown', $.proxy(this.scrollSafety, this)); 
     this.$element.on('blur', $.proxy(this.blur, this)); 
     this.shown = false; 
     return this; 
    } 

    , lookup: function (event) { 
     this.query = this.$element.val(); 
     return this.process(this.source); 
    } 

    , process: function (items) { 
     var that = this; 

     items = $.grep(items, function (item) { 
     return that.matcher(item); 
     }) 

     items = this.sorter(items); 

     if (!items.length) { 
     return this.shown ? this.hide() : this; 
     } 

     return this.render(items.slice(0, this.options.items)).show(); 
    } 

    , template: function() { 
     if (this.options.bsVersion == '2') { 
     return '<div class="combobox-container"><input type="hidden" /> <div class="input-append"> <input type="text" autocomplete="off" /> <span class="add-on dropdown-toggle" data-dropdown="dropdown"> <span class="caret"/> <i class="icon-remove"/> </span> </div> </div>' 
     } else { 
     return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" /> <span class="input-group-addon dropdown-toggle" data-dropdown="dropdown"> <span class="caret" /> <span class="glyphicon glyphicon-remove" /> </span> </div> </div>' 
     } 
    } 

    , matcher: function (item) { 
     return ~item.toLowerCase().indexOf(this.query.toLowerCase()); 
    } 

    , sorter: function (items) { 
     var beginswith = [] 
     , caseSensitive = [] 
     , caseInsensitive = [] 
     , item; 

     while (item = items.shift()) { 
     if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);} 
     else if (~item.indexOf(this.query)) {caseSensitive.push(item);} 
     else {caseInsensitive.push(item);} 
     } 

     return beginswith.concat(caseSensitive, caseInsensitive); 
    } 

    , highlighter: function (item) { 
     var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); 
     return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) { 
     return '<strong>' + match + '</strong>'; 
     }) 
    } 

    , render: function (items) { 
     var that = this; 

     items = $(items).map(function (i, item) { 
     i = $(that.options.item).attr('data-value', item); 
     i.find('a').html(that.highlighter(item)); 
     return i[0]; 
     }) 

     items.first().addClass('active'); 
     this.$menu.html(items); 
     return this; 
    } 

    , next: function (event) { 
     var active = this.$menu.find('.active').removeClass('active') 
     , next = active.next(); 

     if (!next.length) { 
     next = $(this.$menu.find('li')[0]); 
     } 

     next.addClass('active'); 
    } 

    , prev: function (event) { 
     var active = this.$menu.find('.active').removeClass('active') 
     , prev = active.prev(); 

     if (!prev.length) { 
     prev = this.$menu.find('li').last(); 
     } 

     prev.addClass('active'); 
    } 

    , toggle: function() { 
    if (!this.disabled) { 
     if (this.$container.hasClass('combobox-selected')) { 
     this.clearTarget(); 
     this.triggerChange(); 
     this.clearElement(); 
     } else { 
     if (this.shown) { 
      this.hide(); 
     } else { 
      this.clearElement(); 
      this.lookup(); 
     } 
     } 
    } 
    } 

    , scrollSafety: function(e) { 
     if (e.target.tagName == 'UL') { 
      this.$element.off('blur'); 
     } 
    } 
    , clearElement: function() { 
    this.$element.val('').focus(); 
    } 

    , clearTarget: function() { 
    this.$source.val(''); 
    this.$target.val(''); 
    this.$container.removeClass('combobox-selected'); 
    this.selected = false; 
    } 

    , triggerChange: function() { 
    this.$source.trigger('change'); 
    } 

    , refresh: function() { 
    this.source = this.parse(); 
    this.options.items = this.source.length; 
    } 

    , listen: function() { 
     this.$element 
     .on('focus', $.proxy(this.focus, this)) 
     .on('blur',  $.proxy(this.blur, this)) 
     .on('keypress', $.proxy(this.keypress, this)) 
     .on('keyup', $.proxy(this.keyup, this)); 

     if (this.eventSupported('keydown')) { 
     this.$element.on('keydown', $.proxy(this.keydown, this)); 
     } 

     this.$menu 
     .on('click', $.proxy(this.click, this)) 
     .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) 
     .on('mouseleave', 'li', $.proxy(this.mouseleave, this)); 

     this.$button 
     .on('click', $.proxy(this.toggle, this)); 
    } 

    , eventSupported: function(eventName) { 
     var isSupported = eventName in this.$element; 
     if (!isSupported) { 
     this.$element.setAttribute(eventName, 'return;'); 
     isSupported = typeof this.$element[eventName] === 'function'; 
     } 
     return isSupported; 
    } 

    , move: function (e) { 
     if (!this.shown) {return;} 

     switch(e.keyCode) { 
     case 9: // tab 
     case 13: // enter 
     case 27: // escape 
      e.preventDefault(); 
      break; 

     case 38: // up arrow 
      e.preventDefault(); 
      this.prev(); 
      break; 

     case 40: // down arrow 
      e.preventDefault(); 
      this.next(); 
      break; 
     } 

     e.stopPropagation(); 
    } 

    , keydown: function (e) { 
     this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]); 
     this.move(e); 
    } 

    , keypress: function (e) { 
     if (this.suppressKeyPressRepeat) {return;} 
     this.move(e); 
    } 

    , keyup: function (e) { 
     switch(e.keyCode) { 
     case 40: // down arrow 
     case 39: // right arrow 
     case 38: // up arrow 
     case 37: // left arrow 
     case 36: // home 
     case 35: // end 
     case 16: // shift 
     case 17: // ctrl 
     case 18: // alt 
      break; 

     case 9: // tab 
     case 13: // enter 
      if (!this.shown) {return;} 
      this.select(); 
      break; 

     case 27: // escape 
      if (!this.shown) {return;} 
      this.hide(); 
      break; 

     default: 
      this.clearTarget(); 
      this.lookup(); 
     } 

     e.stopPropagation(); 
     e.preventDefault(); 
    } 

    , focus: function (e) { 
     this.focused = true; 
    } 

    , blur: function (e) { 
     var that = this; 
     this.focused = false; 
     var val = this.$element.val(); 
     if (!this.selected && val !== '') { 
     this.$element.val(''); 
     this.$source.val('').trigger('change'); 
     this.$target.val('').trigger('change'); 
     } 
     if (!this.mousedover && this.shown) {setTimeout(function() { that.hide(); }, 200);} 
    } 

    , click: function (e) { 
     e.stopPropagation(); 
     e.preventDefault(); 
     this.select(); 
     this.$element.focus(); 
    } 

    , mouseenter: function (e) { 
     this.mousedover = true; 
     this.$menu.find('.active').removeClass('active'); 
     $(e.currentTarget).addClass('active'); 
    } 

    , mouseleave: function (e) { 
     this.mousedover = false; 
    } 
    }; 

    /* COMBOBOX PLUGIN DEFINITION 
    * =========================== */ 
    $.fn.combobox = function (option) { 
    return this.each(function() { 
     var $this = $(this) 
     , data = $this.data('combobox') 
     , options = typeof option == 'object' && option; 
     if(!data) {$this.data('combobox', (data = new Combobox(this, options)));} 
     if (typeof option == 'string') {data[option]();} 
    }); 
    }; 

    $.fn.combobox.defaults = { 
    bsVersion: '3' 
    , menu: '<ul class="typeahead typeahead-long dropdown-menu"></ul>' 
    , item: '<li><a href="#"></a></li>' 
    }; 

    $.fn.combobox.Constructor = Combobox; 

}(window.jQuery); 

绑定的功能类 '组合框'

<script> 
    $(document).ready(function(){ 
    $(\'.combobox\').combobox(); 
    }); 
    </script> 
+2

我会使用不同的插件,强烈建议满足您的需求,而不是剽窃源代码。 –

第一步是添加这里返回

   if (!this.selected && val !== '') { 
       return; /* 
       this.$element.val(''); 
       this.$source.val('').trigger('change'); 
       this.$target.val('').trigger('change'); 
       */ 
       } 

然后看看有什么突破。

我再这样做

   if (!this.selected && val !== '') { 
        console.log(val,this.source); 
        if (this.source.indexOf(val) ==-1) { 
        this.map[prompt("value to store for "+val+"?",val)]=val; 
        this.source.push(val) 
        } 
        return; 
        /* 
       this.$element.val(''); 
       this.$source.val('').trigger('change'); 
       this.$target.val('').trigger('change'); 
       */ 
       } 

FIDDLE

+0

谢谢@mplungjan为我节省了很多时间。 – redd42

尝试另一种插件,如:https://github.com/steelheaddigital/jquery.ui.combify

要使用它:

<select id="SomeSelect"></select> 
$("#SomeSelect").combify() 
+0

感谢您的建议,我希望我先找到了这个插件。 – redd42