AngularJS 的select 控件的ng-options的使用示例

Using ngOptions In AngularJS

Wednesday, June 19, 2013

The ngOptions directive in AngularJS allows you to build and bind an HTML select element with options to a model property. It’s quite a versatile directive and is smarter than trying to build the select options with ngRepeat since ngOptions is optimized for two way data binding.

There are some tricks, however.

Let’s start with the following simple controller in JavaScript.

var EngineeringController = function ($scope) {
 
     $scope.engineer = {
         name: "Dani" ,
         currentActivity: "Fixing bugs"
     };
 
     $scope.activities =
     [
         "Writing code" ,
         "Testing code" ,
         "Fixing bugs" ,
         "Dancing"
     ];       
};

The goal is to build a drop down list to select an engineer’s current activity.

< div data-ng-controller = "EngineeringController" >
     {{engineer.name}} is currently: {{ engineer.currentActivity}}
     < div >
         Choose a new activity:
         < select data-ng-model = "engineer.currentActivity"
                 data-ng-options = "act for act in activities" >               
         </ select >
     </ div >
</ div >

One of the tricks to using ngOptions is figuring out the expression AngularJS expects. The current value of “act for act in activities” is telling AngularJS to use the value of each entry in the activities array. This syntax against a simple array of strings allows the select element to appear with the engineer’s current activity selected, and if the selected option changes the framework updates the engineer’s current activity (and vice versa).

image

The expression you can use with ngOptions can be quite a bit more advanced (which could be good or bad). For example, instead of using strings let’s use objects to represent an activity.

var EngineeringController = function ($scope) {
 
     $scope.engineer = {
         name: "Dani" ,
         currentActivity: {
             id: 3,
             type: "Work" ,
             name: "Fixing bugs"
         }
     };
 
     $scope.activities =
     [
         { id: 1, type: "Work" , name: "Writing code" },
         { id: 2, type: "Work" , name: "Testing code" },
         { id: 3, type: "Work" , name: "Fixing bugs" },
         { id: 4, type: "Play" , name: "Dancing" }
     ];       
};

And we’ll change the ngOptions expression to build a label for the select option.

< select data-ng-model = "engineer.currentActivity"
         data-ng-options = "a.name +' (' + a.type + ')' for a in activities" >               
</ select >

This produces:

image

Expressions can also create optgroup elements when using a group by in the expression.

< select ng-model = "engineer.currentActivity"
         data-ng-options = "a.name group by a.type for a in activities" >               
</ select >

Which yields:

image

What About The Initial Selection?

When we switched from an array of strings to activities as objects, we lost the ability for the select to show the starting currentActivity as initially selected. If the user selects a new activity the two-way data binding works and the currentActivity is set, but we lost the initial selection. This is because AngularJS is doing reference comparisons and employee.currentActivity might by “Fixing bugs”, but employee.currentActivity != activities[2], so the page starts with an empty selection in the drop down list.

This is a common occurrence since the engineer object and the activities list are most likely de-serialized from HTTP calls and will completely different object graphs.  There is no good solution with the exiting ngOptions directive but to “fix up” the engineer once the engineer and all the possible activities are loaded. Something like the following (which could be shortened with a library like undercore.js).

for ( var i = 0; i < $scope.activities.length; i++) {
     if ($scope.activities[i].id == $scope.engineer.currentActivity.id) {
         $scope.engineer.currentActivity = $scope.activities[i];
         break ;
     }
}

One Last Variation

What if you had objects representing activities but only wanted the Id property of the selected activity instead of the entire activity. The ngOptions expression can handle this scenario, too. Inside the controller would look like this:

$scope.engineer = {
     name: "Dani" ,
     currentActivityId: 3
};
 
$scope.activities =
[
     { id: 1, type: "Work" , name: "Writing code" },
     { id: 2, type: "Work" , name: "Testing code" },
     { id: 3, type: "Work" , name: "Fixing bugs" },
     { id: 4, type: "Play" , name: "Dancing" }
];

And the expression would use a select as value syntax.

< select ng-model = "engineer.currentActivityId"
         data-ng-options = "a.id as a.name group by a.type for a in activities" >               
</ select >

And that concludes this post on ngOptions. I hope you found the topic stimulating, and stayed on the edge of your seat until these final words.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值