Hacking with Angular: 玩转ngOptions指令
jessesang
8年前
<p>首先说说为什么要详细的了解一下这个指令,因为在工作中总是遇到关于下拉选项的一些操作,但是又常常会出现一些问题;基本会遇到下面一些问题:</p> <ul> <li> <p>关于下拉框使用 ng-repeat 或者 ng-options 指令的区别</p> </li> <li> <p>关于下拉框的 <strong>默认选项</strong> 如何设置</p> </li> <li> <p>关于下拉框选项的 <strong>model值</strong> 如何绑定</p> </li> <li> <p>关于下拉框的 <strong>禁用选项</strong> 问题</p> </li> <li> <p>关于下拉框的 <strong>分组</strong> 问题</p> </li> <li> <p>关于下拉框的 <strong>排序</strong> 问题</p> </li> </ul> <p>下面我们就来好好的研究一下 ng-options ,下面的部分就是关于上面问题的解决方案。</p> <p>关于下面的例子详见 <a href="/misc/goto?guid=4959673773309985392" rel="nofollow,noindex">demo</a> , <strong> <a href="/misc/goto?guid=4959673773402495227" rel="nofollow,noindex">原文链接</a> </strong></p> <p>下面的部分没有太按照上面的问题的顺序,但是他们的解决方法都在里面有提及。</p> <p>下拉框的默认选项一般是可以通过使用 ng-init 指令或者在控制器中对 select 的 model 值进行赋值来达到这个目的的。</p> <p>关于使用 ng-repeat 还是 ng-options 的选择,当我们的下拉列表循环的只是一些简单的字符串或者数字的时候,使用这两个指令都是可以的;但是当我们下拉列表循环的是一些比较复杂的数据并且还有一些附带的其它要求的时候,我们应该使用 ng-options 。</p> <ul> <li> <p>使用 select 结合 ng-repeat 指令组成一个含有默认值的下拉列表。</p> <ul> <li> <p>HTML部分</p> <pre> <code class="language-html"><select ng-init="vm.item1 = vm.items1[0]" ng-model="vm.item1"> <option ng-selected="v == vm.items1[0]" value="{{v}}" ng-repeat="v in vm.items1"> {{v}} </option> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript">vm.items1 = [ '选项一', '选项二', '选项三' ];</code></pre> <p>我们使用 ng-repeat 指令对下拉列表的值进行循环,然后使用 ng-init 对 select 的 model 进行初始化。</p> </li> </ul> </li> <li> <p>使用 ng-options 达到和上面一样的效果</p> <ul> <li> <p>HTML部分</p> <pre> <code class="language-html"> <select ng-model="vm.item2" ng-init="vm.item2 = vm.items2[0]" ng-options="v for v in vm.items2"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript">vm.items2 = [1,2,3];</code></pre> <p>下面的部分具体的讲解 ng-options 指令后面使用的复杂的表达式,还需要注意的是,我们使用的是数组作为下拉列表的输出,当然也可以使用对象,详情可以参考 <a href="/misc/goto?guid=4959673773486609909" rel="nofollow,noindex">官网</a></p> </li> </ul> </li> <li> <p>select as label for value in array</p> <ul> <li> <p>首先说明一下上面的表达式中每一项表示的是什么; array 表示的是我们要进行循环的对象数组,</p> <p>value 表示这个数组中的单独一项,也就是一个单独的对象, select 和 label 都是对象中的某一个属性,其中 select 还可以表示整个对象; label 表示的是下拉框中的显示的选项, select 表示下拉框中选中某一个 label 之后下拉框的 model 的值。 通俗一点说就是, label 只是下拉框中表现出来让你选择的选项,而 select 是你选中那个选项之后,下拉列表的值</p> </li> <li> <p>HTML部分</p> <pre> <code class="language-html"><select ng-init="vm.item3 = vm.items3[0].value" ng-options="v.value as v.name for v in vm.items3" ng-model="vm.item3"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript"> vm.items3 = [ {name: '选项一', value: 1}, {name: '选项二', value: 2}, {name: '选项三', value: 3} ];</code></pre> </li> <li> <p>解释一下上面的一些内容,其中 ng-model="vm.item3" 指定了这个下拉框的 model 值,我们使用 ng-init 进行下拉框的初始化 ng-init="vm.item3 = vm.items3[0].value" ,关于 ng-options="v.value as v.name for v in vm.items3" 我们来看一下,其中 v 表示数组中的单个对象, as 左边的值是我们的下拉框选中时的值, as 右边的值是下拉框表面表示选择项。 在这个例子中,我们会看到下拉框给我们的选项是 选项一 , 选项二 , 选项三 ,但是当我们选中 选项一 的时候实际上下拉框的值是 1 也就是 v.value</p> </li> </ul> </li> <li> <p>label group by group for value in array</p> <ul> <li> <p>group by group 的解释,其中前面的 group by 是固定的,后面的 group 使我们分组的依据。</p> </li> <li> <p>HTML部分</p> <pre> <code class="language-html"><select ng-init="vm.item4 = vm.items4[0]" ng-options="v.name group by v.group for v in vm.items4" ng-model="vm.item4"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript">vm.items4 = [ {name: '选项一', value: 1, group: 'A'}, {name: '选项二', value: 2, group: 'A'}, {name: '选项三', value: 3, group: 'A'}, {name: '选项四', value: 4, group: 'B'}, {name: '选项五', value: 5, group: 'B'}, {name: '选项六', value: 6, group: 'C'}, {name: '选项七', value: 7, group: 'C'} ];</code></pre> </li> <li> <p>页面中的表现如下图:</p> <img src="https://simg.open-open.com/show/ecbde1ad4310df3b3466781dcaa451c1.jpg"> <p>关于上面代码的一些解释,可以从上图看到,只要我们把分组的信息写好, angular 会帮助我们处理好分组的事情。</p> </li> </ul> </li> <li> <p>select as label disable when disable for value in array</p> <ul> <li> <p>disabled when disabled , disabled when 是固定的语句,后面的 disabled 是一个条件,如果条件是 true 的话,那么这一项是不可以被选中的。</p> </li> <li> <p>HTML部分</p> <pre> <code class="language-html"><select ng-init="vm.item5 = vm.items5[0].value" ng-options="v.value as v.name disable when v.show for v in vm.items5" ng-model="vm.item5"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript">vm.items5 = [ {name: '选项一', value: 1}, {name: '选项二', value: 2, show: true}, {name: '选项三', value: 3}, {name: '选项四', value: 4, show: true}, {name: '选项五', value: 5} ];</code></pre> </li> <li> <p>页面中的表现如下:</p> <img src="https://simg.open-open.com/show/dd8601676b7e282452822cee4466fbcb.jpg"> <p>可以看到,选项二和选项四是禁用的。</p> </li> </ul> </li> <li> <p>label disable when disable for value in array</p> <ul> <li> <p>HTML部分</p> <pre> <code class="language-html"> <select ng-init="vm.item6 = vm.items6[0]" ng-options="v.name disable when v.show for v in vm.items6" ng-model="vm.item6"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript">vm.items6 = [ {name: '选项一', value: 1}, {name: '选项二', value: 2, show: true}, {name: '选项三', value: 3}, {name: '选项四', value: 4, show: true}, {name: '选项五', value: 5} ];</code></pre> </li> <li> <p>这个例子和上面的很相似,但是还是有一些区别的;这个例子的下拉框的 model 值是一个对象,上面那个例子的下拉框的 model 只是一个数字;从哪里可以看出来呢?因为两个 ng-options 指令后面的表达式是不一样的, 如果表达式中使用了 as 关键字的话那么 as 左边的表达式的值就是我们的下拉框的 model 值,如果不使用的话,默认的就是我们数组中的某一项的值,在此处是一个对象。</p> </li> </ul> </li> <li> <p>label for value in array track by trackexpr</p> <ul> <li> <p>track by 是用来识别数组中的每个对象的,当这个数组再次被重新创建或者更新的时候的时候, 已经选择的选项会被保留下来,也就是说,会保留每一项当时选择的状态 。</p> </li> <li> <p>HTML部分(未使用track by)</p> <pre> <code class="language-html"> <select multiple ng-init="vm.item7 = []" ng-options="v.name for v in vm.items7" ng-model="vm.item7"> </select></code></pre> </li> <li> <p>JavaScript部分(未使用track by)</p> <pre> <code class="language-javascript">vm.items7 = [ {name: '选项一', value: 1, id: 1}, {name: '选项二', value: 2, id: 2}, {name: '选项三', value: 3, id: 3}, {name: '选项四', value: 4, id: 4}, {name: '选项五', value: 5, id: 5} ];</code></pre> </li> <li> <p>JavaScript部分,公用的函数 changeItems 部分</p> <pre> <code class="language-javascript"> function changeItems() { vm.items7 = [ {name: '选项一', value: 1, id: 1}, {name: '选项二', value: 2, id: 2}, {name: '选项三', value: 3, id: 3}, {name: '选项四', value: 4, id: 4}, {name: '选项五', value: 5, id: 5}, {name: '选项6', value: 6, id: 6} ]; vm.items8 = [ {name: '选项一', value: 1, id: 1}, {name: '选项二', value: 2, id: 2}, {name: '选项三', value: 3, id: 3}, {name: '选项四', value: 4, id: 4}, {name: '选项五', value: 5, id: 5}, {name: '选项6', value: 6, id: 6} ]; }</code></pre> </li> <li> <p>HTML部分</p> <pre> <code class="language-html"> <select multiple ng-init="vm.item8 = []" ng-options="v.name for v in vm.items8 track by v.id" ng-model="vm.item8"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript">vm.items8 = [ {name: '选项一', value: 1, id: 1}, {name: '选项二', value: 2, id: 2}, {name: '选项三', value: 3, id: 3}, {name: '选项四', value: 4, id: 4}, {name: '选项五', value: 5, id: 5} ];</code></pre> </li> <li> <p>我们使用了下拉框的 <strong>多选模式</strong> ,这样就可以更清楚地看到我们说的为什么要使用 track by 这个关键字的原因,在demo7中,我们没有使用 track by ,我们将demo7下拉框的 model 值初始化为一个数组,并且有一个辅助的函数 changeItems ,模拟下拉框的选项变化;当我们选中一些选项后,点击更新按钮,会发现之前的选择已经被清零了;当是当我们使用了 track by 之后,就像demo8中的示例那样,当我们选中了一些选项之后,再次点击更新按钮,会发现之前选择的选项依旧还是存在的。</p> </li> </ul> </li> <li> <p>label for value in array | orderBy : expr track by trackexpr</p> <ul> <li> <p>我们也可以在后面的表达式语句中使用 orderBy 过滤器,使用过滤器的好处是,让下拉框的选项按照我们的要求进行进行排列,让我们使用起来更加方便。</p> </li> <li> <p>HTML部分</p> <pre> <code class="language-html"> <select ng-init="vm.item9 = vm.items9[vm.items9.length - 1]" ng-options="v.name for v in vm.items9 | orderBy: ['value'] track by v.id" ng-model="vm.item9"> </select></code></pre> </li> <li> <p>JavaScript部分</p> <pre> <code class="language-javascript"> vm.items9 = [ {name: '选项一', value: 5, id: 1}, {name: '选项二', value: 4, id: 2}, {name: '选项三', value: 3, id: 3}, {name: '选项四', value: 2, id: 4}, {name: '选项五', value: 1, id: 5} ];</code></pre> </li> <li> <p>首先我们的数据部分和上面的不一样,我们将数据中的 value 部分进行了倒序,然后又在表达式中使用 orderBy 过滤器,并且按照 value 值进行排序;关于 orderBy 过滤器的使用方法可以参考 <a href="/misc/goto?guid=4959673773575696961" rel="nofollow,noindex">官网</a> 。还要注意的是,我们也给这个下拉框的 model 初始化了一个值,不然这个下拉框会有一个空白的选项,给用户的的体验很不好;当然我们也是根据数据的特征使用了 ng-init="vm.item9 = vm.items9[vm.items9.length - 1]" 进行初始化。</p> </li> </ul> </li> </ul> <p>关于下拉框要循环的是对象的情况基本上和上面的差不多,大家可以自行看官网上的说明,好了就先到这里了。</p> <p> </p> <p>来自: <a href="/misc/goto?guid=4959673773657746852" rel="nofollow">https://segmentfault.com/a/1190000005342175</a></p> <p> </p>