前言

一.背景

对于select的下拉列表,像国家选拔那样的功能,整个世界那么多国家,一贯拉滚动条多麻烦,眼睛也要看着找,累!所以为优化用户体验,带查找功能的下拉框是老大极度有供给的。都知情jquery里有如此的插件,但大家用的是Angularjs,更期待用双向绑定,指令的措施优雅地消除这么些标题。

对此select的下拉列表,像国家选拔那样的成效,满世界那么多国家,一向拉滚动条多费劲,眼睛也要瞅着找,累!so,为优化用户体验,带查找功用的下拉框是卓殊可怜有须求的。都掌握jquery里有如此的插件,但大家用的是Angularjs,更期待用双向绑定,指令的方法优雅地解决那个标题。

分析

分析:

咱俩的对象是在本来的<select ng-options="">标签上新加贰个属性
select-search
就会支撑查找的作用。倘使这一个本性没起作用,也不影响原来的select的作用。

   目标 在原来的<select ng-options="">标签上新加一个属性 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.在selectSearch一声令下里,怎么获取到ng-options里的数据源,以及钦定的value(option标签的value)text(option标签里的text)字段名。

1.代码有的

    
2.用怎么着点子来筛选?是历次展现匹配项,隐藏不相称项依旧毎次从数额源里相配,重新生成结点。

1.1 js代码(请引先引进jquery,否则会报错)

减轻思路

/**
 * 带筛选功能的下拉框
 * 使用方法 <select ngc-select-search name="select1" ng-options="">
 * 说明[ select 一定要有name,ng-options 属性]
 */
 .directive('ngcSelectSearch', 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('ng-options 表达式有误')
   }
   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 = {
      'optionValues': optionValues,
      'labelArray': labelArray,
      'idArray': idArray
     }
    }
   });
  }
  return {
   restrict: 'A',
   require: ['ngModel'],
   priority: 100,
   replace: false,
   scope: true,
   template: '<div class="chose-container">' +
    '<div class="chose-single"><i class="glyphicon glyphicon-remove"></i></div>' +
    '<div class="chose-drop chose-hide j-drop">' +
    '<div class="chose-search">' +
    '<input class="j-key" type="text" autocomplete="off">' +
    '</div>' +
    '<ul class="chose-result">' +
    // '<li ng-repeat="'+repeatTempl+'" data-id="'+keyTempl+'" >{{'+ valueTempl+'}}</li>'+
    '</ul>' +
    '</div>' +
    '</div>',
   link: {
    pre: function selectSearchPreLink(scope, element, attr, ctrls) {

     var tmplNode = $(this.template).first();

     var modelName = attr.ngModel,
      name = attr.name? attr.name:('def'+Date.now());
     tmplNode.attr('id', name + '_chosecontianer');

     $animate.enter(tmplNode, element.parent(), element);
    },
    post: function selectSearchPostLink(scope, element, attr, ctrls) {
     var choseNode = element.next(); //$('#'+attr.name +'_chosecontianer');
     choseNode.addClass(attr.class);
     element.addClass('chose-hide');
     // 当前选中项
     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 = '';
       choseNode.find('.j-view:first').text('请选择');
       choseNode.find('i').addClass('chose-hide');
      }
      if ((currentKey + '').length > 0) {
       for (var i = 0, l = rs.idArray.length; i < l; i++) {
        if (rs.idArray[i] == currentKey) {
         choseNode.find('.j-view:first').text(rs.labelArray[i]);
         choseNode.find('i').removeClass('chose-hide');
         break;
        }
       }
      }
     }

     function setViewAndData() {
      if (!scope.options) {
       return;
      }
      rs = scope.options;
      setView();
     }
     scope.$watchCollection('options', 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($('<li>').data('id', rs.idArray[i]).text(rs.labelArray[i]))
       }
      }
      return nodes;

     }
     choseNode.on('keyup', '.j-key', function() {
      // 搜索输入框keyup,重新筛选列表
      var value = $(this).val();
      choseNode.find('ul:first').empty().append(getListNodes(value));
      return false;
     }).on('click', function() {
      choseNode.find('.j-drop').removeClass('chose-hide');
      if (choseNode.find('.j-view:first').text() != '请选择') {
       choseNode.find('i').removeClass('chose-hide');
      }
      choseNode.find('ul:first').empty().append(getListNodes(choseNode.find('.j-key').val()));
      return false;
     }).on('click', 'ul>li', function() {
      var _this = $(this);
      ngModelCtrl.$setViewValue(_this.data('id'));
      ngModelCtrl.$render();
      choseNode.find('.j-drop').addClass('chose-hide');
      return false;

     }).on('click', 'i', function() {
      ngModelCtrl.$setViewValue('');
      ngModelCtrl.$render();
      choseNode.find('.j-view:first').text('请选择');
      return false;

     });
     $(document).on("click", function() {
      $('.j-drop').addClass('chose-hide');
      choseNode.find('i').addClass('chose-hide');
      return false;
     });

    }
   }
  };
 })

    
1.仿照效法angular自带指令ng-options来收获数据源和value,text字段名。极其表达,仅援助ng-options="obj.value as obj.text for obj in list"的普通格局,那三个带分组的等等,暂不帮忙哈。

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

     2.重新生成结点。(为啥这么选取,方便啊!)

.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: '';
 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='text'] {
 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;
}

实际达成

1.3 使用及功用

1.代码局地

<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>

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

永利开户送38元体验金 1

/**
  * 带筛选功能的下拉框
  * 使用方法 <select ngc-select-search name="select1" ng-options="">
  * 说明[ select 一定要有name,ng-options 属性]
  */
 .directive('ngcSelectSearch', 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('ng-options 表达式有误')
     }
     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 = {
           'optionValues': optionValues,
           'labelArray': labelArray,
           'idArray': idArray
         }
       }
     });
   }
   return {
     restrict: 'A',
     require: ['ngModel'],
     priority: 100,
     replace: false,
     scope: true,
     template: '<div class="chose-container">' +
       '<div class="chose-single"><i class="glyphicon glyphicon-remove"></i></div>' +
       '<div class="chose-drop chose-hide j-drop">' +
       '<div class="chose-search">' +
       '<input class="j-key" type="text" autocomplete="off">' +
       '</div>' +
       '<ul class="chose-result">' +
       // '<li ng-repeat="'+repeatTempl+'" data-id="'+keyTempl+'" >{{'+ valueTempl+'}}</li>'+
       '</ul>' +
       '</div>' +
       '</div>',
     link: {
       pre: function selectSearchPreLink(scope, element, attr, ctrls) {

         var tmplNode = $(this.template).first();

         var modelName = attr.ngModel,
           name = attr.name? attr.name:('def'+Date.now());
         tmplNode.attr('id', name + '_chosecontianer');

         $animate.enter(tmplNode, element.parent(), element);
       },
       post: function selectSearchPostLink(scope, element, attr, ctrls) {
         var choseNode = element.next(); //$('#'+attr.name +'_chosecontianer');
         choseNode.addClass(attr.class);
         element.addClass('chose-hide');
         // 当前选中项
         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 = '';
             choseNode.find('.j-view:first').text('请选择');
             choseNode.find('i').addClass('chose-hide');
           }
           if ((currentKey + '').length > 0) {
             for (var i = 0, l = rs.idArray.length; i < l; i++) {
               if (rs.idArray[i] == currentKey) {
                 choseNode.find('.j-view:first').text(rs.labelArray[i]);
                 choseNode.find('i').removeClass('chose-hide');
                 break;
               }
             }
           }
         }

         function setViewAndData() {
           if (!scope.options) {
             return;
           }
           rs = scope.options;
           setView();
         }
         scope.$watchCollection('options', 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($('<li>').data('id', rs.idArray[i]).text(rs.labelArray[i]))
             }
           }
           return nodes;

         }
         choseNode.on('keyup', '.j-key', function() {
           // 搜索输入框keyup,重新筛选列表
           var value = $(this).val();
           choseNode.find('ul:first').empty().append(getListNodes(value));
           return false;
         }).on('click', function() {
           choseNode.find('.j-drop').removeClass('chose-hide');
           if (choseNode.find('.j-view:first').text() != '请选择') {
             choseNode.find('i').removeClass('chose-hide');
           }
           choseNode.find('ul:first').empty().append(getListNodes(choseNode.find('.j-key').val()));
           return false;
         }).on('click', 'ul>li', function() {
           var _this = $(this);
           ngModelCtrl.$setViewValue(_this.data('id'));
           ngModelCtrl.$render();
           choseNode.find('.j-drop').addClass('chose-hide');
           return false;

         }).on('click', 'i', function() {
           ngModelCtrl.$setViewValue('');
           ngModelCtrl.$render();
           choseNode.find('.j-view:first').text('请选择');
           return false;

         });
         $(document).on("click", function() {
           $('.j-drop').addClass('chose-hide');
           choseNode.find('i').addClass('chose-hide');
           return false;
         });

       }
     }
   };
 })

2.详实说明

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

次第中的关键点是parseOptions函数,即方今深入分析里的标题1。parseOptions是参谋ng-options的源码实现的,原本是想回去二个对象,这些指标里带有了数据源,然则在调节和测量试验时,开采post函数中该函数重返对象里的多少为空,watch不到,所以改为用scope.options来存多少。

.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: '';
 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='text'] {
 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;
}

以上正是本文的全体内容,希望对我们的学习抱有帮助,也目的在于我们多多支持脚本之家。

动用及效益

你或者感兴趣的篇章:

  • angularjs达成天气预先报告成效
  • Angularjs加多排序查询成效的实例代码
  • 永利开户送38元体验金,AngularJS模糊查询作用达成代码(过滤内容下拉菜单排序过滤敏感字符验证推断后增添表格消息)
  • mongoDB 多种数组查询(AngularJS绑定呈现nodejs)
  • Angularjs分页查询的贯彻
  • 对待分析Django的Q查询及AngularJS的Datatables分页插件
  • Bootstrap + AngularJS
    完结简单的数量过滤字符查找功用
  • Angularjs达成带查找筛选成效的select下拉框示例代码
  • Angular达成的简约询问天气预先报告作用示例
<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来存数据。

总结

上述正是那篇文章的全体内容,希望本文的内容对大家的求学只怕办事能带来一定的支持,借使有疑问我们能够留言沟通。

你也许感兴趣的小说:

  • Angular实现的停放过滤器orderBy排序与模糊查询功效示例
  • Angular实现的自定义模糊查询、排序及三角箭头申明成效示例
  • AngularJS模糊查询功效达成代码(过滤内容下拉菜单排序过滤敏感字符验证判断后增加表格新闻)
  • AngularJS使用ng-repeat指令达成下拉框
  • AngularJS使用ng-options指令达成下拉框
  • Angular.JS中select下拉框设置value的不二秘诀
  • Angularjs达成下拉框联合浮动的示范代码
  • Angular.js中下拉框完毕渲染html的点子
  • AngularJS中下拉框的尖端用法示例
  • AngularJS中下拉框的主干用法示例
  • Angular完毕下拉框模糊查询作用示例

相关文章