摘要:
如果LookUp字段里引用的列表数据超过20条的时候,Lookup字段将不通过Select标记进行输出,而是通过Textbox进行输出,微软希望提供的Textbox可以为用户提供输入过滤的功能,但是相应带来的问题却是用户需要通过双击而不是单击来选择Lookup下拉列表的内容,用户体验上并不友好。本文将通过Javascript的方式提供用户单击选择超长列表的方案。还有两种思路,一种是写一个自己的Lookup字段,注意Lookup字段不能被继承;另一种思路是通过控件的Adapter来改变输出时的行为。
问题介绍:
如下图所示,我们可以看到第一个Test1字段引用的列表只有19条数据,但是Test2引用的列表却又近百条数据,显而易见的是两个下拉列表的样式并不一样,而且选择Test2下拉列表内容的时候我们会发现需要点击两次相应两目才能选中。
解决思路:
我们查看HTML代码回发现针对Test1字段输出内容如下,采用的是HTML Select元素:
但针对Test2字段输出内容如下,采用的是类型为Text的Input元素:
进一步的我们查看Test2字段的HTML代码,我们会发现有几点内容值得关注:
optHid属性:此属性指定了存储选中项目ID的隐藏控件;
choices属性:此属性包含了需要显示的文本以及背后ID的所有信息;
match属性:此属性包含被选中的内容的信息;
当点击下拉列表的小箭头时实际调用了一个叫做showdropdown的方法,此方法来源于core.js文件,进一步的查看showdropdown方法的代码我们会发现这个方法调用EnsureSelectElement来在当前文本框后面添加一个Select元素来实现的,紧接着通过FilterChoice方法来为Select元素添加选项值,最后Select内容选择好以后调用SetCtrlFromOpt方法将文本内容设置到Text元素的Match属性,此外在FilterChoice还会将文本内容对应的Value值设置到Text元素的OptHid属性指定的隐藏控件里。最后再在Js中将值设置到Text元素文本框中。
因而我们的思路是在画面加载结束后通过Javascript脚本生成一个Select元素,并通过choices里的内容将其初始化,然后设置其onchange事件,确保新的内容被选择后相应的值会设置到原始的文本框里,这样保存的时候就能够存到SharePoint里去,最后我们通过属性设置隐藏掉原始的文本框。
解决步骤:
第一步,引入JQuery库(可至Jquey.com网站下载),通过SharePoint Designer上传到相关列表的文件夹内,再通过SharePoint Designer打开newform.aspx页面,在PlaceHolderMain里面加入对该库的引用,例如:
<script type="text/javascript" src="jquery-1.6.1.min.js" > </script>
第二步,添加代码如下:
<script type="text/javascript"> $(document).ready(function() { var ctrl1 = $("input[title='Test2']") var ctrl = document.getElementById(ctrl1.attr('id')); ctrl.style.display="none"; var select=document.createElement("SELECT"); ctrl.parentNode.appendChild(select); select.outerHTML="<select id='“+ ctrl.opt + “' ctrl='"+ctrl.id+"' class='ms-lookuptypeindropdown' name='” + ctrl.opt + “'></select>"; var opt = document.getElementById(ctrl.opt); FillChoice(opt, ctrl, ""); });
首先我们通过JQuery的选择器获得了对原始的Test2字段的引用,紧接着我们通过此ID获得了对文本框控件本身的引用(有兴趣的朋友可以直修改剩余的代码完全通过Jquery来操作,本人为了图省事,大多数代码沿用SharePoint core.js里的内容),然后隐藏了该文本框控件,接着创建了一个Select元素,然后调用自定义的FillChoice方法对Select元素进行了初始化,该方法的算法借鉴了core.js的ilterChoice方法。
function FillChoice(opt, ctrl, strVal) { var i; var strName=opt.name; var strHtml=""; var strId=opt.id; var strOpts=ctrl.choices; var rgopt=strOpts.split("|"); var x=AbsLeft(ctrl); var y=AbsTop(ctrl)+ctrl.offsetHeight; var iMac=rgopt.length - 1; for (i=0; i < rgopt.length; i=i+2) { var strOpt=rgopt[i]; while (i < iMac - 1 && rgopt[i+1].length==0) { strOpt=strOpt+"|"; i++; if (i < iMac - 1) { strOpt=strOpt+rgopt[i+1]; } i++; } var strValue=rgopt[i+1]; var strLowerOpt=strOpt.toLocaleLowerCase(); var strLowerVal=strVal.toLocaleLowerCase(); if (strLowerOpt.indexOf(strLowerVal)==0) { strHtml+="<option value=\""+strValue+"\">"+STSHtmlEncode(strOpt)+"</option>"; } } var strHandler=" onchange=HandleClick()"; var strOptHtml=""; strOptHtml="<select tabIndex='-1' ctrl='"+ctrl.id+"' name='"+strName+"' id='"+strId+"'"+strHandler; strOptHtml+=" style='position:absolute;z-index:2;left:"+x+"px;top:"+y+"px'>"+strHtml+"</select>"; opt.outerHTML=strOptHtml; } function HandleClick() { var opt = event.srcElement; var ctrl = document.getElementById(opt.ctrl); SetCtrlFromOpt(ctrl, opt); }
FillChoice方法通过提取原始文本框控件的choices属性值初始化了自定义的Select列表选项,注意onchange事件指定为HandleClick处理器。HandleClick事件调用core.js的SetCtrlFromOpt方法进行值得设置。
效果查看:
保存后我们可以发现第二个字段的样式已经与正常小于20条时的样式一致且可以正常保存列表。
说明:
该解决方案没有针对Firefox进行测试。