首页 >web前端 >js教程 >Angularjs实现带查找筛选功能的select下拉框示例代码

Angularjs实现带查找筛选功能的select下拉框示例代码

高洛峰
高洛峰原创
2016-12-29 10:29:161464浏览

前言

对于select的下拉列表,像国家选择这样的功能,全世界那么多国家,一直拉滚动条多辛苦,眼睛也要盯着找,累!所以为优化用户体验,带查找功能的下拉框是非常非常有必要的。都知道jquery里有这样的插件,但我们用的是Angularjs,更希望用双向绑定,指令的方式优雅地解决这个问题。

分析

我们的目标是在原来的329787504acd75e22a9ffe9ecf0c1ee0标签上新加一个属性 select-search 就能支持查找的功能。如果这个属性没起作用,也不影响原来的select的功能。

问题

     1.在selectSearch指令里,怎么获取到ng-options里的数据源,以及指定的value(option标签的value)和text(option标签里的text)字段名。

     2.用什么方式来筛选?是每次显示匹配项,隐藏不匹配项还是毎次从数据源里匹配,重新生成结点。

解决思路

     1.参考angular自带指令ng-options来获取数据源和value,text字段名。特别说明,仅支持ng-options="obj.value as obj.text for obj in list"的普通形式,那些带分组的等等,暂不支持哈。

     2.重新生成结点。(为什么这么选择,方便呀!)

具体实现

1.代码部分

1.1 js代码(请引先引入jquery,不然会报错)

/**
  * 带筛选功能的下拉框
  * 使用方法 <select ngc-select-search name="select1" ng-options="">
  * 说明[ select 一定要有name,ng-options 属性]
  */
 .directive(&#39;ngcSelectSearch&#39;, function($animate, $compile, $parse) {
 
   function parseOptions(optionsExp, element, scope) {
     // ngOptions里的正则
     var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?(?:\s+disable\s+when\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/;
 
     var match = optionsExp.match(NG_OPTIONS_REGEXP);
     if (!(match)) {
       console.log(&#39;ng-options 表达式有误&#39;)
     }
     var valueName = match[5] || match[7];
     var keyName = match[6];
     var displayFn = $parse(match[2]);
     var keyFn = $parse(match[1]);
     var valuesFn = $parse(match[8]);
 
     var labelArray = [],
       idArray = [],
       optionValues = [];
     scope.$watch(match[8], function(newValue, oldValue) {
       if (newValue && newValue.length > 0) {
         optionValues = valuesFn(scope) || [];
         labelArray = [];
         idArray = []
         for (var index = 0, l = optionValues.length; index < l; index++) {
           var it = optionValues[index];
           if (match[2] && match[1]) {
             var localIt = {};
             localIt[valueName] = it;
             var label = displayFn(scope, localIt);
             var dataId = keyFn(scope, localIt);
             labelArray.push(label);
             idArray.push(dataId);
           }
         }
 
         scope.options = {
           &#39;optionValues&#39;: optionValues,
           &#39;labelArray&#39;: labelArray,
           &#39;idArray&#39;: idArray
         }
       }
     });
   }
   return {
     restrict: &#39;A&#39;,
     require: [&#39;ngModel&#39;],
     priority: 100,
     replace: false,
     scope: true,
     template: &#39;<div class="chose-container">&#39; +
       &#39;<div class="chose-single"><span class="j-view"></span><i class="glyphicon glyphicon-remove"></i></div>&#39; +
       &#39;<div class="chose-drop chose-hide j-drop">&#39; +
       &#39;<div class="chose-search">&#39; +
       &#39;<input class="j-key" type="text" autocomplete="off">&#39; +
       &#39;</div>&#39; +
       &#39;<ul class="chose-result">&#39; +
       // &#39;<li ng-repeat="&#39;+repeatTempl+&#39;" data-id="&#39;+keyTempl+&#39;" >{{&#39;+ valueTempl+&#39;}}</li>&#39;+
       &#39;</ul>&#39; +
       &#39;</div>&#39; +
       &#39;</div>&#39;,
     link: {
       pre: function selectSearchPreLink(scope, element, attr, ctrls) {
 
         var tmplNode = $(this.template).first();
 
         var modelName = attr.ngModel,
           name = attr.name? attr.name:(&#39;def&#39;+Date.now());
         tmplNode.attr(&#39;id&#39;, name + &#39;_chosecontianer&#39;);
 
         $animate.enter(tmplNode, element.parent(), element);
       },
       post: function selectSearchPostLink(scope, element, attr, ctrls) {
         var choseNode = element.next(); //$(&#39;#&#39;+attr.name +&#39;_chosecontianer&#39;);
         choseNode.addClass(attr.class);
         element.addClass(&#39;chose-hide&#39;);
         // 当前选中项
         var ngModelCtrl = ctrls[0];
         if (!ngModelCtrl || !attr.name) return;
 
         parseOptions(attr.ngOptions, element, scope);
         var rs = {};
 
         function setView() {
           var currentKey = ngModelCtrl.$modelValue;
           if (isNaN(currentKey) || !currentKey) {
             currentKey = &#39;&#39;;
             choseNode.find(&#39;.j-view:first&#39;).text(&#39;请选择&#39;);
             choseNode.find(&#39;i&#39;).addClass(&#39;chose-hide&#39;);
           }
           if ((currentKey + &#39;&#39;).length > 0) {
             for (var i = 0, l = rs.idArray.length; i < l; i++) {
               if (rs.idArray[i] == currentKey) {
                 choseNode.find(&#39;.j-view:first&#39;).text(rs.labelArray[i]);
                 choseNode.find(&#39;i&#39;).removeClass(&#39;chose-hide&#39;);
                 break;
               }
             }
           }
         }
 
         function setViewAndData() {
           if (!scope.options) {
             return;
           }
           rs = scope.options;
           setView();
         }
         scope.$watchCollection(&#39;options&#39;, setViewAndData);
         scope.$watch(attr.ngModel, setView);
 
 
         function getListNodes(value) {
           var nodes = [];
           value = $.trim(value);
           for (var i = 0, l = rs.labelArray.length; i < l; i++) {
             if (rs.labelArray[i].indexOf(value) > -1) {
               nodes.push($(&#39;<li>&#39;).data(&#39;id&#39;, rs.idArray[i]).text(rs.labelArray[i]))
             }
           }
           return nodes;
 
         }
         choseNode.on(&#39;keyup&#39;, &#39;.j-key&#39;, function() {
           // 搜索输入框keyup,重新筛选列表
           var value = $(this).val();
           choseNode.find(&#39;ul:first&#39;).empty().append(getListNodes(value));
           return false;
         }).on(&#39;click&#39;, function() {
           choseNode.find(&#39;.j-drop&#39;).removeClass(&#39;chose-hide&#39;);
           if (choseNode.find(&#39;.j-view:first&#39;).text() != &#39;请选择&#39;) {
             choseNode.find(&#39;i&#39;).removeClass(&#39;chose-hide&#39;);
           }
           choseNode.find(&#39;ul:first&#39;).empty().append(getListNodes(choseNode.find(&#39;.j-key&#39;).val()));
           return false;
         }).on(&#39;click&#39;, &#39;ul>li&#39;, function() {
           var _this = $(this);
           ngModelCtrl.$setViewValue(_this.data(&#39;id&#39;));
           ngModelCtrl.$render();
           choseNode.find(&#39;.j-drop&#39;).addClass(&#39;chose-hide&#39;);
           return false;
 
         }).on(&#39;click&#39;, &#39;i&#39;, function() {
           ngModelCtrl.$setViewValue(&#39;&#39;);
           ngModelCtrl.$render();
           choseNode.find(&#39;.j-view:first&#39;).text(&#39;请选择&#39;);
           return false;
 
         });
         $(document).on("click", function() {
           $(&#39;.j-drop&#39;).addClass(&#39;chose-hide&#39;);
           choseNode.find(&#39;i&#39;).addClass(&#39;chose-hide&#39;);
           return false;
         });
 
       }
     }
   };
 })

1.2 css代码(用less写的,以下是编译后的)

.chose-hide {
 position: absolute!important;
 top: -999em !important;
}
.chose-container {
 border: none!important;
 float: left;
 margin-right: 40px;
 padding: 0!important;
 position: relative;
}
.chose-container .chose-single {
 padding: 6px 12px;
 color: #333;
 width: 100%;
 border: 1px solid #eee;
 display: inline-block;
 height: 30px;
}
.chose-container .chose-single::after {
 content: &#39;&#39;;
 position: absolute;
 border-width: 6px 3px;
 border-style: solid;
 /* border-top-color: transparent; */
 border-left-color: transparent;
 border-right-color: transparent;
 border-bottom-color: transparent;
 right: 8px;
 top: 12px;
}
.chose-container .chose-single i {
 width: 12px;
 float: right;
 right: 8px;
 font-size: 12px;
 height: 12px;
 background-color: #eee;
}
.chose-container .chose-drop {
 width: 195px;
 position: absolute;
 border: 1px solid #eee;
 z-index: 1000;
 background-color: #fff;
}
.chose-container .chose-search input[type=&#39;text&#39;] {
 margin: 0;
 padding-left: 12px;
 width: 100%;
 height: 30px;
 border: 1px solid #ccc;
 float: none;
}
.chose-container .chose-result {
 max-height: 370px;
 overflow-y: scroll;
 overflow-x: hidden;
}
.chose-container .chose-result li {
 padding: 5px 12px;
 list-style-type: none;
}
.chose-container .chose-result li:hover {
 background-color: #e1e2e7;
}

使用及效果

<select ngc-select-search class="common-select" ng-model="aa.b" ng-options="obj.countryId as obj.countryCnName for obj in vm.countries" name="country">
<option value="">请选择</option></select>

详细说明

程序中的关键点是parseOptions函数,即前面分析里的问题1。parseOptions是参考ng-options的源码实现的,原来是想返回一个对象,这个对象里包含了数据源,但是在调试时,发现post函数中该函数返回对象里的数据为空,watch不到,所以改为用scope.options来存数据。

总结

以上就是这篇文章的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。


更多Angularjs实现带查找筛选功能的select下拉框示例代码相关文章请关注PHP中文网!


声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn