原文: https://www.gurustop.net/blog/2014/01/28/common-problems-and-solutions-when-using-select-elements-with-angular-js-ng-options-initial-selection/

------------------------------------------------------------------------------------------------------------------------

I have been doing Angular.JS in production projects for months, that it did surprise me recently how I haven’t used drop-downs in it. Well, I mean how I haven’t used them enough to get into several problems I had in my current project, and other friends at the same office had in their project as well.

To save you the pain I went through, I’ll list some problems and solutions here, and then give you a video that shows going through all of them ans the thought process that led to the solutions.

 

Initial selection

  1. <code><select ng-model="myModel.someObject"
  2. ng-options="someObject.text for someObject in objectList ">
  3. </select>
  4. </code>
 

Assuming someObject in the model has the same properties and values as someObject in the objectList, it will still not be selected.

It’ll only be selected if someObject was actually one of the objects in objectList, like objectList[0] or whatever. Otherwise, Angular.JS will insert an empty option tag with no value or text and select that.

Root Cause

Angular.JS uses native JavaScript comparison for comparing the objects. In JavaScript, unrelated to Angular.JS or anything, comparing objects (object literals) is “by reference”, so it doesn’t factor the similarity of the objects. Only checks if the two references compared point to the same object in memory or not.

Solution

An un-documented (AFAIK) feature in ng-options is that you can use some bits from the ng-repeat directive with it, like track by. This allows us to choose some property as the comparison key.

  1. <code><select ng-model="myModel.someObject"
  2. ng-options="someObject.text for someObject in objectList track by someObject.key">
  3. </select>
  4. </code>
 

If the key property is a simple type, like Number or string, JavaScript will consider it equal to any other object that has the same value, so we don’t have to use the same objects.

Invalid Value Sent On Server-Side Submit

When Angular.JS writes the <option> tags from an ng-options directive pointing to an array, the value of the option is always the index of the element it maps to in the array. This is not important if you process the selection on client side because you only deal with the result of ng-model anyway, you can use this later to create an AJAX request or whatever.

However, if you intend to submit the form using a normal server submission, and only use Angular.JS for say validation or managing complex form interaction (client-side tables containing sub-items with add/remove/sort for example), this may be a road blocker to using Angular.

Root Cause

By default Angular.JS uses the index of the array to track which object maps to which <option> element.

Solution

Similar to the previous problem, use the track by syntax. Angular.JS will use the track by property value as the <option>‘s value. Most of the time your tracked property is the key property you want to send to the server anyway, so, this should be good enough.

Simple Properties Scenario When Combined With Server-Side Submit

Let’s say you want something as simple as this:

  1. <code><select
  2. ng-model="person.genderId"
  3. ng-options="gender.id as gender.text for gender in genders">
  4. </select>
  5. </code>
 

This syntax will work very well, if you only use this value from JavaScript, you are all set. But if you plan to send it directly to the server (a normal non-AJAX form submit), you’ll want to consider using the track by syntax, like track by gender.id.

However, if you do this, you’ll notice that the select is no longer usable. No initial selection, and changing selection although updates the model, it does not show the new selected value.

Root Cause

The track by syntax expects an object, with the property you use to track. It does not honor the key part used in the key as text syntax (which in our example is g.id as g.text), so, it wants the ng-model to point to an object with the tracked property, it cannot be the key itself directly.

Workaround

I didn’t call this a solution, because it’s pretty much a hack.

  1. <code><select
  2. ng-init="person._gender = {id: person.genderId}"
  3. ng-change="person.genderId = person._gender.id"
  4. ng-model="person._gender"
  5. ng-options="gender.id as gender.text
  6. for gender in genders track by gender.id">
  7. </select>
  8. </code>
 

We created a new property (which I liked to prefix with _ to show it doesn’t normally belong to the model object), initialized it to a new object that contains only our key property id set to the original simple value genderId, and then used that as the model (as in ng-model).

We created and assigned the property in ng-init, then synchronized the changes to the simple property via ng-change. This allows the code everywhere else in the application (like the controller, or other parts of the markup) to only interact with the property we want (genderId in this example), without knowing about our hack. This makes things a bit cleaner, although it still remains a hack rather than a solution.

You can view an example of using this hack here.

Adding extra selection items to the dropdown

One thing you notice if you are affected by the “initial selection” problem, is that the empty <option> tag that Angular.JS adds when it can’t match the ng-model to the array from ng-options disappears when the use changes their selection. We have gone through how to avoid showing the empty option by mistake already.

But if you do want to have that option, it’s easy, just, um, add it!

  1. <code><select ng-model="myModel.someObject"
  2. ng-options="someObject.text for someObject in
  3. objectList track by someObject.key">
  4. <option value="">-- Select an option--</option>
  5. </select>
  6. </code>
 

Update:

If you are using Angular 1.4+, check the much smaller 2nd part of this article, about how to use track by correctly.
Using track by correctly with Angular 1.4 select ng-options – Why can’t I select this option?

The Video

If you want to dig these problems really deep and see what they look like in action, and what was the thought process for solving them like and in some cases other possible solutions, I have put all this in a (rather long) video here:

How to set the initial value of a select element using AngularJS ng-options & track by的更多相关文章

  1. 使控件具有 Tilt 效果

    步骤1:添加类: /* Copyright (c) 2010 Microsoft Corporation. All rights reserved. Use of this sample source ...

  2. Django之Form组件

    Django之Form组件 本节内容 基本使用 form中字段和插件 自定义验证规则 动态加载数据到form中 1. 基本使用 django中的Form组件有以下几个功能: 生成HTML标签 验证用户 ...

  3. ABAP 订单-交货单-发货过账自动完成 案例

    *&---------------------------------------------------------------------* *& Report  ZSDR006 ...

  4. SAP 订单状态跟踪

    *&--------------------------------------------------------------------- *& Program name:  *& ...

  5. 【Django】--Form组件

    Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面显示内容 例子: 1.创建Form类 from djan ...

  6. ABAP 订单转交货单

    *& Report  ZSDR025 *& *&---------------------------------------------------------------- ...

  7. jqGrid配置属性说明

    Property Type Description Default1) ajaxGridOptions object This option allows to set global ajax set ...

  8. django--forms

    forms模块的功能 1 表单提交验证 2 生成HTML标签 其他 提交后保留页面数据 创建forms类 首先从django中引入forms,一般会在application中新建一个文件专门保存for ...

  9. javascript 手势缩放 旋转 拖动支持:hammer.js

    原文: https://cdn.rawgit.com/hammerjs/hammer.js/master/tests/manual/visual.html /*! Hammer.JS - v2.0.4 ...

随机推荐

  1. 用HashMap优化斐波那契数列 java算法

    斐波那契是第一项为0,第二项为1,以后每一项是前面两项的和的数列. 源码:Fibonacci.java public class Fibonacci{ private static int times ...

  2. body标签相关

    03-body标签中相关标签   今日主要内容: 列表标签 <ul>.<ol>.<dl> 表格标签 <table> 表单标签 <fom> 一 ...

  3. luogu3369 【模板】普通平衡树(Treap/SBT) treap splay

    treap做法,参考hzwer的博客 #include <iostream> #include <cstdlib> #include <cstdio> using ...

  4. [错误解决]刚拿到的服务器vim退格键(backspace)失灵

    刚拿到的服务器vim退格键(backspace)失灵: 解决方案: 在主目录下建立.vimrc 覆盖/etc/vimrc的配置 .vimrc 与 /etc/vimrc的区别: 在启动的时候vim会读取 ...

  5. 为什么在header 和 session 之前不能有输出

    1.在header输出之前有输出内容的话,就会造成对header的错误理解(尽管现在已经能容错了),例如不是满足“keyword: value\n”的格式还好,直接错误了,但是满足“keyword: ...

  6. JAVA接口与抽象类区别

    接口 1.接口可以继承多个接口,extends 接口1,接口2,接口3 2.接口的成员变量默认是public static abstract,必须初始化的: 3.接口只能有抽象方法,继承接口的类必须实 ...

  7. HDU——1418抱歉(平面欧拉公式)

    抱歉 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submiss ...

  8. 如何在 Windows 上 使用 ONLYOFFICE 协作编辑文档

    ONLYOFFICE Document Server提供文档协作的服务功能,支持Word,Excel和PowerPoint的协作.但是这里告诉我们,需要进行文档管理和存储的二次开发. Please n ...

  9. [luoguP1129] [ZJOI2007]矩阵游戏(二分图最大匹配)

    传送门 每一行的1和每一列的1不管怎么换还是在同一行和同一列 目标状态中有n个1是不同行且不同列的 那么就是能否找出n个不同行不同列的1 就是每一行选一个不同列的1 如果矩阵中位置i,j为1,那么点i ...

  10. 手动创建DataTable并绑定gridview

    原文发布时间为:2008-08-04 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...