使用 AngularJS 的 ng-options 进行选择

Posted

技术标签:

【中文标题】使用 AngularJS 的 ng-options 进行选择【英文标题】:Working with select using AngularJS's ng-options 【发布时间】:2012-10-14 10:00:15 【问题描述】:

我在其他帖子中读到过,但我无法弄清楚。

我有一个数组,

$scope.items = [
   ID: '000001', Title: 'Chicago',
   ID: '000002', Title: 'New York',
   ID: '000003', Title: 'Washington',
];

我想把它渲染成:

<select>
  <option value="000001">Chicago</option>
  <option value="000002">New York</option>
  <option value="000003">Washington</option>
</select>

我还想选择 ID=000002 的选项。

我已阅读select并尝试过,但我无法弄清楚。

【问题讨论】:

我强烈推荐使用Select2,因为它会为你处理这个问题。甚至还有a directive for AngularJS。 github.com/angular/angular.js/issues/6564 其实有一个由QuantumUI开发的纯AngularJS解决方案。您可以在 http://quantumui.org/ 找到更多示例和文档。 【参考方案1】:

需要注意的一点是 ngModel 是 必需 ngOptions 才能工作...注意 ng-model="blah" 表示“将 $scope.blah 设置为所选值”。

试试这个:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

这里有更多来自 AngularJS 的文档(如果你还没有看过的话):

对于数组数据源:

数组中的值标签 选择作为数组中值的标签 按组标记数组中的值 = 为数组中的值按组选择标签

对于对象数据源:

对象中(键、值)的标签 选择作为对象中(键、值)的标签 按组标记对象中的(键、值) 按组为对象中的(键、值)选择标签

关于 AngularJS 中的选项标签值的一些说明:

当你使用ng-options 时,ng-options 写出的选项标签的值将始终是选项标签所关联的数组项的索引。这是因为 AngularJS 实际上允许您使用选择控件选择整个对象,而不仅仅是原始类型。例如:

app.controller('MainCtrl', function($scope) 
   $scope.items = [
      id: 1, name: 'foo' ,
      id: 2, name: 'bar' ,
      id: 3, name: 'blah' 
   ];
);
<div ng-controller="MainCtrl">
   <select ng-model="selectedItem" ng-options="item as item.name for item in items"></select>
   <pre>selectedItem | json</pre>
</div>

以上将允许您直接选择整个对象到$scope.selectedItem重点是,使用 AngularJS,您无需担心选项标签中的内容。让 AngularJS 处理它;您应该只关心您的模型中的内容。

Here is a plunker demonstrating the behavior above, and showing the html written out


处理默认选项:

关于默认选项,我在上面没有提到一些事情。

选择第一个选项并删除空选项:

您可以通过添加一个简单的ng-init 来做到这一点,它将模型(来自ng-model)设置为您在ng-options 中重复的项目中的第一个元素:

<select ng-init="foo = foo || items[0]" ng-model="foo" ng-options="item as item.name for item in items"></select>

注意:如果 foo 恰好被正确初始化为“虚假”的东西,这可能会有点疯狂。在这种情况下,您很可能需要在控制器中处理 foo 的初始化。

自定义默认选项:

这有点不同;在这里,您需要做的就是添加一个选项标签作为您选择的子项,具有空值属性,然后自定义其内部文本:

<select ng-model="foo" ng-options="item as item.name for item in items">
   <option value="">Nothing selected</option>
</select>

注意:在这种情况下,即使您选择了不同的选项,“空”选项也会保留在那里。 AngularJS 下选择的默认行为不是这种情况。

选择后隐藏的自定义默认选项:

如果您希望自定义的默认选项在您选择一个值后消失,您可以在默认选项中添加一个 ng-hide 属性:

<select ng-model="foo" ng-options="item as item.name for item in items">
   <option value="" ng-if="foo">Select something to remove me.</option>
</select>

【讨论】:

原来这些是值的索引,这就是角度如何允许您使用对象作为选择框的值。 Angular 在幕后使用选择框为您做了很多事情,您不必担心选项中的 value 属性。 文档在他们网站上的“选择”下:docs.angularjs.org/api/ng.directive:select "...ngModel 是 ngOptions 工作所必需的..." 对我来说是问题的症结所在。很好的答案。 是否可以避免第一个空选项(&lt;option value="?" selected="selected"&gt;&lt;/option&gt;)? 我正在尝试使用最后一种情况(选择后隐藏的自定义默认选项)但我发现了一些问题。而不是ng-if="foo"我必须使用ng-if=!foo隐藏其他选项时隐藏默认的空选项。此外,默认的空选项始终出现在组合列表的底部。我怎样才能把它放在组合列表的开头?【参考方案2】:

我正在学习 AngularJS,并且也在努力选择。我知道这个问题已经得到解答,但我还是想分享更多代码。

在我的测试中,我有两个列表框:汽车品牌和汽车型号。模型列表被禁用,直到选择了某些品牌。如果稍后重置品牌列表框中的选择(设置为“选择品牌”),则模型列表框将再次禁用,并且其选择也将重置(为“选择模型”)。品牌作为资源被检索,而模型只是硬编码。

制作 JSON:

[
"code": "0", "name": "Select Make",
"code": "1", "name": "Acura",
"code": "2", "name": "Audi"
]

services.js:

angular.module('makeServices', ['ngResource']).
factory('Make', function($resource)
    return $resource('makes.json', , 
        query: method:'GET', isArray:true
    );
);

HTML 文件:

<div ng:controller="MakeModelCtrl">
  <div>Make</div>
  <select id="makeListBox"
      ng-model="make.selected"
      ng-options="make.code as make.name for make in makes"
      ng-change="makeChanged(make.selected)">
  </select>

  <div>Model</div>
  <select id="modelListBox"
     ng-disabled="makeNotSelected"
     ng-model="model.selected"
     ng-options="model.code as model.name for model in models">
  </select>
</div>

controllers.js:

function MakeModelCtrl($scope)

    $scope.makeNotSelected = true;
    $scope.make = selected: "0";
    $scope.makes = Make.query(, function (makes) 
         $scope.make = selected: makes[0].code;
    );

    $scope.makeChanged = function(selectedMakeCode) 
        $scope.makeNotSelected = !selectedMakeCode;
        if ($scope.makeNotSelected)
        
            $scope.model = selected: "0";
        
    ;

    $scope.models = [
      code:"0", name:"Select Model",
      code:"1", name:"Model1",
      code:"2", name:"Model2"
    ];
    $scope.model = selected: "0";

【讨论】:

尊敬的随机用户。虽然这个问题及其答案相当简单且不复杂,但您将代码组织到其适当和相应的位置(控制器、服务、模板、数据)以最简单和默认的形式展示了 AngularJS 的优雅。很棒的例子。 这不是它的用途。 ng-model 应该指向你范围内的另一个变量,与make 无关。请参阅docs.angularjs.org/api/ng/directive/ngOptions 中的示例 @DmitriZaitsev 我认为你错了,只是因为角度文档示例以你描述的方式显示它并不意味着这是唯一的方法。向我们展示为什么您认为不应该以这种方式使用它,而不是为新手垃圾一个很好的例子。【参考方案3】:

由于某种原因,AngularJS 让我感到困惑。他们的文档在这方面非常糟糕。欢迎提供更多好的变体示例。

无论如何,我对 Ben Lesh 的回答略有不同。

我的数据集如下所示:

items =
[
    key:"AD",value:"Andorra" 
,   key:"AI",value:"Anguilla" 
,   key:"AO",value:"Angola" 
 ...etc..
]

现在

<select ng-model="countries" ng-options="item.key as item.value for item in items"></select>

仍然导致选项值成为索引(0、1、2 等)。

添加 Track By 为我修复了它:

<select ng-model="blah" ng-options="item.value for item in items track by item.key"></select>

我认为您想将一组对象添加到选择列表中的情况经常发生,所以我会记住这个!

请注意,从 AngularJS 1.4 开始,您不能再使用 ng-options,但您需要在选项标签上使用 ng-repeat

<select name="test">
   <option ng-repeat="item in items" value="item.key">item.value</option>
</select>

【讨论】:

这个答案似乎正是问题所要求的。每个其他答案都告诉读者不要担心会生成什么 HTML,但是如果选择元素在表单中,我会非常担心。很好的答案! 需要指出的是,这将全选对象存储在模型中,而不仅仅是键。如果您只需要模型中的键,则需要使用“item.key as item.value”版本。这让我困惑了一段时间,因为我对 HTML 的外观感兴趣,而不是模型中我想要的数据,这对我来说是重要的事情。 @mhenry1384 是的,你是对的,关于它存储整个对象。我实际上喜欢这个功能,因为它让您可以访问的不仅仅是 ID(如果您需要的话。)。当我使用 mongo 集合填充列表并且我需要所选项目的一些属性时,这对我来说效果很好。 我们如何检测option 中的“ng-change”变化? 关于更新,这看起来不对。 ng-options 在 1.5 中仍然可以正常工作。它也仍然显示在文档中。 docs.angularjs.org/api/ng/directive/select【参考方案4】:

这个问题已经回答了(顺便说一句,Ben 提供了非常好的和全面的答案),但我想添加另一个元素以确保完整性,这可能也非常方便。

在 Ben 建议的示例中:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

已使用以下ngOptions 表单:select as label for value in array

Label 是一个表达式,其结果将是&lt;option&gt; 元素的标签。在这种情况下,您可以执行某些字符串连接,以获得更复杂的选项标签。

例子:

ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" 给你像Title - ID 这样的标签 ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items" 为您提供Title (X) 之类的标签,其中X 是标题字符串的长度。

你也可以使用过滤器,例如,

ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items" 为您提供类似 Title (TITLE) 的标签,其中 Title 属性的 Title 值和 TITLE 是相同的值,但转换为大写字符。 ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items" 给你像Title (27 Sep 2015) 这样的标签,如果你的模型有一个属性SomeDate

【讨论】:

【参考方案5】:

在 CoffeeScript 中:

#directive
app.directive('select2', ->
    templateUrl: 'partials/select.html'
    restrict: 'E'
    transclude: 1
    replace: 1
    scope:
        options: '='
        model: '='
    link: (scope, el, atr)->
        el.bind 'change', ->
            console.log this.value
            scope.model = parseInt(this.value)
            console.log scope
            scope.$apply()
)
<!-- HTML partial -->
<select>
  <option ng-repeat='o in options'
          value='$index' ng-bind='o'></option>
</select>

<!-- HTML usage -->
<select2 options='mnuOffline' model='offlinePage.toggle' ></select2>

<!-- Conclusion -->
<p>Sometimes it's much easier to create your own directive...</p>

【讨论】:

不要忘记您的radixparseInt:http://davidwalsh.name/parseint-radix【参考方案6】:

如果您需要为每个选项自定义标题,ng-options 不适用。而是使用带有选项的ng-repeat

<select ng-model="myVariable">
  <option ng-repeat="item in items"
          value="item.ID"
          title="Custom title: item.Title [item.ID]">
       item.Title
  </option>
</select>

【讨论】:

【参考方案7】:

我希望以下内容对你有用。

<select class="form-control"
        ng-model="selectedOption"
        ng-options="option.name + ' (' + (option.price | currency:'USD$') + ')' for option in options">
</select>

【讨论】:

【参考方案8】:

它可能很有用。绑定并不总是有效。

<select id="product" class="form-control" name="product" required
        ng-model="issue.productId"
        ng-change="getProductVersions()"
        ng-options="p.id as p.shortName for p in products"></select>

例如,您从 REST 服务填充选项列表源模型。一个选定的值在填充列表之前是已知的,并且它已被设置。使用 $http 执行 REST 请求后,列表选项就完成了。

但未设置所选选项。由于未知原因,影子 $digest 执行中的 AngularJS 没有按应有的方式绑定选择。我必须使用 jQuery 来设置所选内容。这很重要! AngularJS,在阴影中,将前缀添加到由 ng-repeat 选项生成的 attr“值”的值。对于 int,它是“数字:”。

$scope.issue.productId = productId;
function activate() 
    $http.get('/product/list')
       .then(function (response) 
           $scope.products = response.data;

           if (productId) 
               console.log("" + $("#product option").length);//for clarity
               $timeout(function () 
                   console.log("" + $("#product option").length);//for clarity
                   $('#product').val('number:'+productId);

               , 200);
           
       );

【讨论】:

以上是关于使用 AngularJS 的 ng-options 进行选择的主要内容,如果未能解决你的问题,请参考以下文章

使用 AngularJS 的 ng-options 进行选择

使用 AngularJS 的 ng-options 进行选择

编写自定义指令以在 AngularJS (TypeScript) 中向 ng-options 添加工具提示

编写自定义指令以将工具提示添加到AngularJS中的ng-options(TypeScript)

Angularjs:ng-options group by

Angularjs:ng-options group by