[Ext JS 4] 实战之多选下拉单 (带checkbox) 续 - 带ALL 选项

前言

[Ext JS 4] 实战之多选下拉单 (带checkbox)

这一篇中有介绍如何开发带有checkbox 的多选菜单。

但是实际项目开发过程中, 用户的需求也是不断精进的。

使用淘宝或是其他网站购物车功能的用户对全选就特别习惯, 所以他们也希望在下拉单中也能有  "ALL" 这样的选项。

但是Extjs 本身提供的多选下拉单,功能比较有限。

之前有扩充过带 checkbox, 现在又要多扩充一个 "ALL" 选项了。

要求是:

1. 选中"ALL", 其他选项要自动勾选

2. 反选"ALL", 其他选项要自动反选

3. 所有非"ALL"选项都选了, 要自动把 "ALL"勾选

3. 有一个非"ALL"选项选项反选了, 要自动反选 "ALL"

思考思路

要扩充,首先得要有一个思路。

思路1 : 在store 中加入一个ALL 的数据,

很简单的一个store

	var store1 = Ext.create(‘Ext.data.Store‘, {
	    fields: [‘abbr‘, ‘name‘],
	    data : [
	        {"abbr":"ALL", "name":"All"},
	        {"abbr":"AL", "name":"Alabama"},
	        {"abbr":"AK", "name":"Alaska"},
	        {"abbr":"AZ", "name":"Arizona"}
	    ]

这样的确有一个 ALL 选项, 但是这个ALL 选项和其他选项的作用是一样的。

但是 "ALL" 本身的意义有不一样, 无法达到上面提到的要求。

思路2: 能否在下拉单中增加一个选项, 但是这个选项又和一般的选项不一样, 也就是说它不属于Extjs 的combobox 的选项, 只是添加一个 html 的input 元素, 设置他的onclik 事件, 并与其他的选项进行联动。

Extjs combox 的结构基本上是

1. 显示的input 框和 trigger 的按钮

2. BoundList , 类似于grid 的view , 用来显示下拉单。(可以想象成下拉单是只有一个栏位的 grid)

BoundList 的配置可以在combobox 的listConfig 配置选项中进行配置, 这样的话, 就可以配置显示的template 了

配置类似:

 tpl:	‘<div class="mt-boundlist-item" onclick="clickAllOptionDiv(\‘‘+thisid+‘\‘)"><input onclick="clickAllOptionInput(this)" type="checkbox" id="‘+allOptId+‘">ALL</div>
<tpl for="."><div class="x-boundlist-item"><input type=checkbox>{‘+this.displayField+‘}</div></tpl>‘,

这里配置了整个BoundList的显示格式:

1. 有一个 ALL 选项, 并有相应的 onclick 时间

2. 配置了每个选项的显示效果(带有一个checkbox)

显示部分解决之后, 接下来就是, 联动的处理,

在BoundList 的 onItemSelect 和 onItemDeselect 去处理 ALL 的选项是否要选取。

需要注意的是,

1.因为这里有给ALL  选项的id 为 combobox 的id 加上一些字符, 所以在创建combobox 的时候, 需要指定id

.2. ALL选项的div class 设置成 mt-boundlist-item 目的是为了和其他选项的显示效果一致。

这个Class 的定义如下:

<style>
.mt-boundlist-item {
  padding: 0 6px;
  line-height: 22px;
  cursor: pointer;
  cursor: hand;
  position: relative;
  /*allow hover in IE on empty items*/
  zoom: 1;
  border-width: 1px;
  border-style: dotted;
  border-color: white;
}
</style>
<script>

这个内容和Extjs 本身的 x-boundlist-Item是一样的, 只是ALL选项的Class 不能用那个Class(因为用了, 就会被当成一般的选项)

代码

/*********************************
 * @author: Oscar999
 * @Description: New Widgets Extend from Ext
 * @verion: V1.0
 **********************************/

/**
 * begin for multi Select combobox
 */
Ext.define(‘Ext.ux.MultiComboBox‘, {
    extend: ‘Ext.form.ComboBox‘,
    alias: ‘widget.multicombobox‘,
    xtype: ‘multicombobox‘,
    validate:function() {
	    var errs =[];
	    var val = this.getRawValue();
	    if (this.store.data && this.store.data.items.length>0){
	        if (this.xtype=="multicombobox"){
	        	var ssRawValues=[];
	        	if (val){
		        	if ((this.id==="projectList")||val.indexOf(", ")>0){
		        		ssRawValues=val.split(", ");
		        	}
		        	else{
		        		ssRawValues=val.split(",");
		        	}
	        	}
	        	for(var ii=0;ii<ssRawValues.length;ii++){
	        		var selectedValue=ssRawValues[ii];
	        		if (ssRawValues[ii].trim){
	        			selectedValue=ssRawValues[ii].trim();
	        		}else if (trim){
	        			selectedValue=trim(selectedValue);
	        		}
		        	var rec = this.findRecord(this.displayField, selectedValue);
		        	if(!rec)
		                errs.push("Invalid Selection ["+ ssRawValues[ii]+"]");
	        	}

	        }
	        else{
	        	var rec = this.findRecord(this.displayField, val);
	        	if(!rec)
	                errs.push("Invalid Selection");
	        }
	    }
	    if(errs && errs.length > 0)
		{
			var error = errs[0];
			this.markInvalid(error);
	        return false;
		}else if(!this.allowBlank && !val){
			this.markInvalid(this.getErrors());
			return false;
		}
		else{
			this.clearInvalid();
	        return true;
		}
    },
    clearValue:function(){
   	 //var coboxhtml = this.getEl().getHTML();
   	 try{
   	     var coboxhtml = this.getEl().dom;
   	   	 if(coboxhtml!=null)
   	     {
   	   		 var checkboxs = this.picker.listEl.el.dom.children;
   	   		 if(checkboxs!=null)
   	   		 {
   	       		 for(var i=0;i<checkboxs.length;i++)
   	           	 {
   	               	 var checkbox = checkboxs[i];

   	               	 checkbox.children[0].checked = false;
   	           	 }
   	   		 }
   	      }
   	 }catch(e)
   	 {
   		if(typeof(console)!="undefined"&&console!=null)
   		{
   			console.log(e.toString());
   		}
   	 }
      this.setValue([]);
   },
    initComponent: function(){
    	var valueField = this.valueField;
    	this.multiSelect = true;
    	var me = this;
    	var thisid = this.id;
    	var allOptId = thisid+"_allOpt";
        this.allOptId = allOptId;
    	this.listConfig = {
    	     tpl:	‘<div class="mt-boundlist-item" onclick="clickAllOptionDiv(\‘‘+thisid+‘\‘)"><input onclick="clickAllOptionInput(this)" type="checkbox" id="‘+allOptId+‘">ALL</div><tpl for="."><div class="x-boundlist-item"><input type=checkbox>{‘+this.displayField+‘}</div></tpl>‘,
	  	     onItemSelect: function(record) {
	  	    	  var node = this.getNode(record);
    	          if (node) {
    	             Ext.fly(node).addCls(this.selectedItemCls);

    	             var checkboxs = node.getElementsByTagName("input");
    	             if(checkboxs!=null)
    	             {
    	            	 var checkbox = checkboxs[0];
  	    				 checkbox.checked = true;
    	             }
    	          }
    			 var isAllSelected = true;
    			 var store = this.getStore();
    			 if(store!=null&&store.getTotalCount()>0)
    			 {
  	    			 for(var i=0;i<store.getTotalCount();i++)
  	    			 {
  	    				 var recordTemp = store.getAt(i);
  	    				 var itemTemp = this.getNode(recordTemp);
  	    				 var isSelectedTemp = this.isSelected(itemTemp);
  	    				 if(!isSelectedTemp){
   	    					isAllSelected = false;
  	    					break;
  	    				 }
  	    			 }
    			 }else{
    				isAllSelected = false;
    			 }

    			 if(isAllSelected)
    			 {
    				me.selectAllOpt();
    			 }
	  	      },
	  	    onItemDeselect: function(record) {
	  	    	var node = this.getNode(record);
  	            if (node) {
  	            	 Ext.fly(node).removeCls(this.selectedItemCls);

  	             var checkboxs = node.getElementsByTagName("input");
  	             if(checkboxs!=null)
  	             {
  	            	 var checkbox = checkboxs[0];
	    				 checkbox.checked = false;
	    			 me.deselectAllOpt();

  	             }
  	            }
	  	    },
	  	      listeners:{
  	    		  itemclick:function(view, record, item, index, e, eOpts ){
  	    			  var isSelected = view.isSelected(item);
  	    			  var checkboxs = item.getElementsByTagName("input");
  	    			  if(checkboxs!=null)
  	    			  {
  	    				  var checkbox = checkboxs[0];
  	    				  if(!isSelected)
  	    				  {
  	    					  checkbox.checked = true;
  	    				  }else{
  	    					  checkbox.checked = false;
  	    				  }
  	    			  }
  	    		  }
	  	      }
	  	}
    	this.callParent();
    },

    deselectAllOpt:function()
    {
    	var allOptInput = document.getElementById(this.allOptId);
    	if(allOptInput!=null)
    	{
    		allOptInput.checked =false;
    	}
    },
    selectAllOpt:function()
    {
    	var allOptInput = document.getElementById(this.allOptId);
    	if(allOptInput!=null)
    	{
    		allOptInput.checked =true;
    	}
    }    

});

function clickAllOptionDiv(comboxId)
{
	if(comboxId!=null&&comboxId.length>0)
	{
		var allOptInputId = comboxId+"_allOpt";
		var allOptInput = document.getElementById(allOptInputId);
		clickAllOptionInput(allOptInput);
	}
}

function clickAllOptionInput(allOptInput)
{
	if(allOptInput!=null)
	{
		var allOptInputId = allOptInput.id;
		var allOptInputIdArray = allOptInputId.split("_allOpt");
		var comboxId = allOptInputIdArray[0];
		var isChecked = allOptInput.checked;
		var combobox = Ext.getCmp(comboxId);
		var boundList = combobox.getPicker();
		if(boundList!=null)
		{
			var selModel = boundList.getSelectionModel();
			selModel.deselectOnContainerClick=false;
		}
		var allValueArray = getAllStoreValueArryByAtt(combobox.getStore(),combobox.valueField);
		if(isChecked)
		{
			allOptInput.checked=false;
			if(combobox!=null)
			{
				combobox.setValue([]);
			}
		}else{
			allOptInput.checked=true;
			if(combobox!=null)
			{
				combobox.setValue(allValueArray);
			}
		}
	}
}

function getAllStoreValueArryByAtt(store,key)
{
	var valueArray = [];
	if(store!=null)
	{
		for(var i=0;i<store.getTotalCount();i++)
		{
			var record = store.getAt(i);
			if(record.get(key)!=null)
			{
				valueArray.push(record.get(key));
			}
		}
	}
	return valueArray;
}

/**
 * end for multi Select combobox
 */

贴一下全部的代码。

调用的方式如下:

	var store1 = Ext.create(‘Ext.data.Store‘, {
	    fields: [‘abbr‘, ‘name‘],
	    data : [
	        //{"abbr":"ALL", "name":"All"},
	        {"abbr":"AL", "name":"Alabama"},
	        {"abbr":"AK", "name":"Alaska"},
	        {"abbr":"AZ", "name":"Arizona"}
	        //...
	    ]
	});

	Ext.create(‘Ext.ux.MultiComboBox‘,{
		fieldLabel:‘Multi Combox 1‘,
		id:‘nulticombox1‘, //must
		renderTo:‘combox‘,
		//queryMode:‘local‘,
		width:600,
		displayField:‘name‘,
		valueField:‘abbr‘,
		value:[‘AL‘],
		store:store1
	});

实现的效果如下:

继续

其实,问题到以上基本上以及介绍了。

但是正如上面看到的。

有的用户认为, 全选的话, 应该显示成ALL,而不是其他的所有选项。

这样的需求也算合理, 改进一般, 直接上源码

/*********************************
 * @author: Oscar999
 * @Description: New Widgets Extend from Ext
 * @verion: V1.0
 **********************************/

/**
 * begin for multi Select combobox
 */
Ext.define(‘Ext.ux.MultiComboBox‘, {
    extend: ‘Ext.form.ComboBox‘,
    alias: ‘widget.multicombobox‘,
    xtype: ‘multicombobox‘,
    validate:function() {
	    var errs =[];
	    var val = this.getRawValue();
	    if (this.store.data && this.store.data.items.length>0){
	        if (this.xtype=="multicombobox"){
	        	var ssRawValues=[];
	        	if (val){
		        	if ((this.id==="projectList")||val.indexOf(", ")>0){
		        		ssRawValues=val.split(", ");
		        	}
		        	else{
		        		ssRawValues=val.split(",");
		        	}
	        	}
	        	for(var ii=0;ii<ssRawValues.length;ii++){
	        		var selectedValue=ssRawValues[ii];
	        		if (ssRawValues[ii].trim){
	        			selectedValue=ssRawValues[ii].trim();
	        		}else if (trim){
	        			selectedValue=trim(selectedValue);
	        		}
	        		if(selectedValue!="ALL")
	        		{
			        	var rec = this.findRecord(this.displayField, selectedValue);
			        	if(!rec)
			                errs.push("Invalid Selection ["+ ssRawValues[ii]+"]");
	        		}
	        	}

	        }
	        else{
	        	var rec = this.findRecord(this.displayField, val);
	        	if(!rec)
	                errs.push("Invalid Selection");
	        }
	    }
	    if(errs && errs.length > 0)
		{
			var error = errs[0];
			this.markInvalid(error);
	        return false;
		}else if(!this.allowBlank && !val){
			this.markInvalid(this.getErrors());
			return false;
		}
		else{
			this.clearInvalid();
	        return true;
		}
    },
    clearValue:function(){
   	 //var coboxhtml = this.getEl().getHTML();
   	 try{
   	     var coboxhtml = this.getEl().dom;
   	   	 if(coboxhtml!=null)
   	     {
   	   		 var checkboxs = this.picker.listEl.el.dom.children;
   	   		 if(checkboxs!=null)
   	   		 {
   	       		 for(var i=0;i<checkboxs.length;i++)
   	           	 {
   	               	 var checkbox = checkboxs[i];

   	               	 checkbox.children[0].checked = false;
   	           	 }
   	   		 }
   	      }
   	 }catch(e)
   	 {
   		if(typeof(console)!="undefined"&&console!=null)
   		{
   			console.log(e.toString());
   		}
   	 }
      this.setValue([]);
   },
    initComponent: function(){
    	var valueField = this.valueField;
    	this.multiSelect = true;
    	this.queryMode = ‘local‘;
    	var me = this;
    	var thisid = this.id;
    	var allOptId = thisid+"_allOpt";
        this.allOptId = allOptId;
        this.setRawValue =function(value) {
            var me = this;
            value = Ext.value(me.transformRawValue(value), ‘‘);
            me.rawValue = value;

            var isAllValue = false;
            var allOptInput = document.getElementById(this.allOptId);
        	if(allOptInput!=null)
        	{
        		if(allOptInput.checked)
        		{
        			isAllValue = true;
        		}
        	}
        	var disvalue = value;
        	//this.setRawValue("ALL");
            // Some Field subclasses may not render an inputEl
            if (me.inputEl) {

                if(isAllValue)
                {
                	disvalue = "ALL";
                	this.suspendCheckChange++;
                	allOptInput.checked = true;
                }
                me.inputEl.dom.value = disvalue;
            }
            return disvalue;
        },
    	this.listConfig = {
    	     tpl:	‘<div class="mt-boundlist-item" onclick="clickAllOptionDiv(\‘‘+thisid+‘\‘)"><input onclick="clickAllOptionInput(this)" type="checkbox" id="‘+allOptId+‘">ALL</div><tpl for="."><div class="x-boundlist-item"><input type=checkbox>{‘+this.displayField+‘}</div></tpl>‘,
	  	     onItemSelect: function(record) {
	  	    	  var node = this.getNode(record);
    	          if (node) {
    	             Ext.fly(node).addCls(this.selectedItemCls);

    	             var checkboxs = node.getElementsByTagName("input");
    	             if(checkboxs!=null)
    	             {
    	            	 var checkbox = checkboxs[0];
  	    				 checkbox.checked = true;
    	             }
    	          }
    			 var isAllSelected = true;
    			 var store = this.getStore();
    			 if(store!=null&&store.getTotalCount()>0)
    			 {
  	    			 for(var i=0;i<store.getTotalCount();i++)
  	    			 {
  	    				 var recordTemp = store.getAt(i);
  	    				 var itemTemp = this.getNode(recordTemp);
  	    				 var isSelectedTemp = this.isSelected(itemTemp);
  	    				 if(!isSelectedTemp){
   	    					isAllSelected = false;
  	    					break;
  	    				 }
  	    			 }
    			 }else{
    				isAllSelected = false;
    			 }

    			 if(isAllSelected)
    			 {
    				me.selectAllOpt();
    			 }
	  	      },
	  	    onItemDeselect: function(record) {
	  	    	var node = this.getNode(record);
  	            if (node) {
  	            	 Ext.fly(node).removeCls(this.selectedItemCls);

  	             var checkboxs = node.getElementsByTagName("input");
  	             if(checkboxs!=null)
  	             {
  	            	 var checkbox = checkboxs[0];
	    				 checkbox.checked = false;
	    			 me.deselectAllOpt();

  	             }
  	            }
	  	    },
	  	      listeners:{
  	    		  itemclick:function(view, record, item, index, e, eOpts ){
  	    			  var isSelected = view.isSelected(item);
  	    			  var checkboxs = item.getElementsByTagName("input");
  	    			  if(checkboxs!=null)
  	    			  {
  	    				  var checkbox = checkboxs[0];
  	    				  if(!isSelected)
  	    				  {
  	    					  checkbox.checked = true;
  	    				  }else{
  	    					  checkbox.checked = false;
  	    				  }
  	    			  }
  	    		  },show:function(view, eOpts ){
  	    			  if(me.getRawValue()=="ALL")
  	    			  {
  	    				 view.getSelectionModel().selectAll(view.getStore());
  	    				 //me.selectAllOpt();
  	    			  }
  	    		  }
	  	      }
	  	}
    	this.callParent();
    },

    deselectAllOpt:function()
    {
    	var allOptInput = document.getElementById(this.allOptId);
    	if(allOptInput!=null)
    	{
    		allOptInput.checked =false;
    	}
    },
    selectAllOpt:function()
    {
    	var allOptInput = document.getElementById(this.allOptId);
    	if(allOptInput!=null)
    	{
    		allOptInput.checked =true;
    	}
    	//this.setRawValue("ALL");
    }    

});

function clickAllOptionDiv(comboxId)
{
	if(comboxId!=null&&comboxId.length>0)
	{
		var allOptInputId = comboxId+"_allOpt";
		var allOptInput = document.getElementById(allOptInputId);
		clickAllOptionInput(allOptInput);
	}
}

function clickAllOptionInput(allOptInput)
{
	if(allOptInput!=null)
	{
		var allOptInputId = allOptInput.id;
		var allOptInputIdArray = allOptInputId.split("_allOpt");
		var comboxId = allOptInputIdArray[0];
		var isChecked = allOptInput.checked;
		var combobox = Ext.getCmp(comboxId);
		var boundList = combobox.getPicker();
		if(boundList!=null)
		{
			var selModel = boundList.getSelectionModel();
			selModel.deselectOnContainerClick=false;
		}
		var allValueArray = getAllStoreValueArryByAtt(combobox.getStore(),combobox.valueField);
		if(isChecked)
		{
			allOptInput.checked=false;
			if(combobox!=null)
			{
				combobox.setValue([]);
			}
		}else{
			allOptInput.checked=true;
			if(combobox!=null)
			{
				combobox.setValue(allValueArray);
			}
		}
		if(combobox.allOptClickFun!=null)
			combobox.allOptClickFun();
	}
}

function getAllStoreValueArryByAtt(store,key)
{
	var valueArray = [];
	if(store!=null)
	{
		for(var i=0;i<store.getTotalCount();i++)
		{
			var record = store.getAt(i);
			if(record.get(key)!=null)
			{
				valueArray.push(record.get(key));
			}
		}
	}
	return valueArray;
}

/**
 * end for multi Select combobox
 */

实现效果

时间: 2024-10-29 10:46:20

[Ext JS 4] 实战之多选下拉单 (带checkbox) 续 - 带ALL 选项的相关文章

[Ext JS 4] 实战之Chart 坐标控制(单坐标,双坐标)

前言 在Extjs 中, 单一的 Column Chart 的展示效果如上. 定义的步骤如下: 1.  创建一个 Ext.chart.Chart 2. 创建两个坐标轴, axes 一个 Category 类型的横坐标用来显示日期 一个Numeric 类型的纵坐标用来显示数据 3. 配置显示的图 series 配置 column 类型的柱状图. 具体代码如下: <!-- Author : oscar999 Date : ALL RIGHTS RESERVED --> <!DOCTYPE h

js获取所选下拉框已经checkbox框内容的方法以及后台如何存储

function say() {  var p = "";  $("input:checkbox[name='checks']:checked").each(function() {    p += $(this).val() + ",";  });  $("#atype").val(p);  var se = "";  $("select option:selected").each(

[Ext JS 4] 实战之Load Mask - 在Grid Reconfigure的使用状况

前言 关于 Extjs 的 load mask 的使用,可以参考: [Ext JS 4] 实战之Load Mask(加载遮罩)的显示与隐藏 一般而言,在如下情况下可能要使用grid 的 reconfigure功能: 1. 改变grid 的显示栏位 (增加或更换, 这和 hide , show 已经有的栏位不同) 2. 切换grid 的View 和 Edit 模式(这里面的内容就比较多了) 这里要讨论的问题是: 在 reconfigure 的时候, grid 是否可以有 load mask 的遮罩

[Ext JS 4] 实战之Load Mask(加载遮罩)的显示与隐藏

前言 Load Mask(遮罩)效果,就是在页面还没有完全显示出来之前, 加上一个转装转的效果. 类似: 添加这样的效果有两个好处: 1. 在页面没完全show出来之前, 把后面的页面给遮罩起来, 防止进行一些非法的操作. 2. 如果页面show出来的时间比较长的话, 可以暂时吸引用户的注意力(也就是提高 User Experience). 在Extjs 中, Ext js 的使用方式有多种. 你有可能会发现为什么有的状况下load mask 不出现?  且听下面一一道来... JsonStor

用jquery实现可输入多选下拉组合框

[写在前面的话]网站上很多用各种插件,比如依赖bootstrap的bootstrap-select插件等.虽然这些框架可以实现很多功能,但因为在实际项目中,可能只会用到其中的某个功能,若是一概引入,会导致整个js加载过于笨重.比如前面提到的bootstrap-select插件,在不压缩的情况下,达到300多k.因此,为了实现一个可填写的下拉框有点得不偿失. 基于这种原因,于是私下用jquery写了一个比较简单的多选下拉可填写组合框. CSS Code: 1 container{ 2 margin

query多选下拉框插件 jquery-multiselect(修改)

其实网上关于该控件的使用教程已经很多了,其中 query多选下拉框插件 jquery-multiselect Jquery多选下拉列表插件jquery multiselect功能介绍及使用 这2个的介绍已经比较详细了,尤其是第二个有扩展MyValues函数,只是扩展有些bug,这里我在提出一些我的扩展,我们应该把multiValues属性定义在options里面,让每个multiselect控件都有自己的multiValues属性.我这里还需要一个获取text的方法.有关Myvalues和Myt

自定义Angular指令与jQuery实现的Bootstrap风格数据双向绑定的单选&amp;多选下拉框

先说点闲话,熟悉Angular的猿们会喜欢这个插件的. 00.本末倒置 不得不承认我是一个喜欢本末倒置的人,学生时代就喜欢先把晚交的作业先做,留着马上就要交的作业不做,然后慢悠悠做完不重要的作业,卧槽,XX作业马上要交了,赶紧补补补.如今做这个项目,因为没找到合适的多选下拉Web插件,又不想用html自带的丑陋的<select multiple></select>,自己花了一整天时间做了一个.或许这样占用的主要功能开发的时间,开发起来会更有紧迫感吧.感觉自己是个抖M自虐倾向,并且伴

Html 多选下拉框

1.css文件 span.dropList {display:inline-block; height:20px;border:1px solid #ccc;  cursor:pointer; background:url(../images/xj.png) #fff no-repeat center right; font-size:12px; line-height:20px;padding-right:10px; position:relative;} span.dropList .Che

页面多选下拉框 jquery.multiple.select

1.首先引用jquery.multiple.select.js.multiple-select.css 2.在页面select下拉列表里面加一个multiple="multiple" <select name="nimbusHost" id="nimbusHost" multiple="multiple"> <c:forEach items="${stormIps}" var="