AngularJS 中对象保留 Key/Value 关联的按字母顺序排列的选项

Alphabetize Options from Object Preserving Key/Value Associations in AngularJS

我需要的是能够按文本对 select 元素的子选项节点进行排序,同时保持它们的值关联。我可以让他们按字母顺序排列并与他们的键解除关联,或者我可以不按字母顺序关联他们的键。

我知道有一种方法可以直接访问 JSON,但这是分阶段实施的,该功能将在稍后推出。现在,我必须在加载应用程序脚本 MyInterface.js 时通过先行脚本块加载 json。

我研究了自定义过滤器,但这就是与键分离的来源。如果 JSON 需要采用完全不同的格式,我愿意采用它。

这是我得到的...

HTML

<!doctype html>
<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
  </head>
  <body>
    <div ng-app="MyInterface" ng-controller="SimpleJSON">
      <select name="index_category"
        ng-model="IndexCategory"
        ng-init="IndexCategory = IndexCategory || '0'"
        ng-options="option in JSON.Categories | orderObjectBy:'val'">
        <option value="0">Select Animal...</option>
      </select>
    </div>
    <script>
      var json = {
        "123":"Zebra",
        "456":"Monkey",
        "789":"Anteater"
      };
    </script>
    <script src="MyInterface.js"></script>
  </body>
</html>

MyInterface.js

(function(json) {

  // AngularJS Module
  var MyInterface = angular.module('MyInterface', []);

  // Custom Filters
  MyInterface.filter('orderObjectBy', function() {
    return function(items, field, reverse) {
      var filtered = [];
      angular.forEach(items, function(item) {
        filtered.push(item);
      });
      filtered.sort(function(a, b) {
        return a[field] > b[field] ? 1 : -1;
      });
      if(reverse) filtered.reverse();
      return filtered;
    };
  });

  // Controllers
  MyInterface.controller('SimpleJSON', function($scope) {
    $scope.JSON = angular.fromJson(json);
  });

})(json);

本质上,selection 在选项方面需要的是:

<option value="0">Select Animal...</option>
<option value="789">Anteater</option>
<option value="456">Monkey</option>
<option value="123">Zebra</option>

包含已接受答案的更改

HTML

<!doctype html>
<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
  </head>
  <body>
    <div ng-app="MyInterface" ng-controller="SimpleJSON">
      <select name="index_category"
        ng-model="IndexCategory"
        ng-options="option.value for option in JSON track by option.key">
        <option value="">Select Animal...</option>
      </select>
    </div>
    <script>
      var json = [
        { key:"123", value:"Zebra" },
        { key:"456", value:"Monkey" },
        { key:"789", value:"Anteater" }
      ];
    </script>
    <script src="MyInterface.js"></script>
  </body>
</html>

MyInterface.js

(function(json) {

  // AngularJS Module
  var MyInterface = angular.module('MyInterface', []);

  // Controllers
  MyInterface.controller('SimpleJSON', function($scope, orderByFilter) {

    // Load JSON
    $scope.JSON = angular.fromJson(json);

    // Alphabetize by Value
    $scope.JSON = orderByFilter($scope.JSON, 'value');

  });

})(json);

您需要使用带有 ng-options 的对象数组。 即,示例

 $scope.animals= [
    {key:"123", value:"Zebra"},
    {key:"456",value: "Monkey"},
    {key:"789", value: "Anteater"}
  ];

并且由于您只想在 ng-model 中输入关键字,因此您需要使用语法 ng-options="option.key as option.value for option in animals | orderBy:'value'"。对于默认选项,只需提供 value=""

选项
<select name="index_category" ng-model="IndexCategory" ng-options="option.key as option.value for option in animals| orderBy:'value'">
    <option value="">Select Animal...</option>
</select>

演示

angular.module('app', []).controller('ctrl', function($scope) {
  $scope.JSON = [{
    key: "123",
    value: "Zebra"
  }, {
    key: "456",
    value: "Monkey"
  }, {
    key: "789",
    value: "Anteater"
  }];

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <select name="index_category" ng-model="IndexCategory" ng-options="option.key as option.value for option in JSON | orderBy:'value'">
    <option value="">Select Animal...</option>
  </select>
  {{IndexCategory}}
</div>

您还需要记住 DOM 过滤器很昂贵,因为它们 运行 在摘要周期中至少两次。如果您的 select 列表是动态的,请不要放置 DOM 过滤器,而是您可以在绑定数据之前在控制器中对其进行排序。在您的情况下,您可以在控制器中使用简单的本机排序或 orderBy 过滤器本身。

angular.module('app', []).controller('ctrl', function($scope, orderByFilter) {
  $scope.animals= [{
    key: "123",
    value: "Zebra"
  }, {
    key: "456",
    value: "Monkey"
  }, {
    key: "789",
    value: "Anteater"
  }];
  /*Using orderByFilter*/
  $scope.animals= orderByFilter($scope.JSON, 'value');
  /*Or just use native sort*/
  //$scope.animals.sort(function(a, b){ return a['value'] > b['value'] });

});

你的观点将是:

 ng-options="option.key as option.value for option in animals">

如果您没有从服务器获取数组格式数据的选项并且需要转换,只需在您的控制器中执行此操作,例如:

$scope.animals = convertToOptions(optionsObject);

function convertToOptions(obj){
    var options = [];
    angular.forEach(obj, function(value, key){
        options.push({key:key, value:value});
    });
    return options;
  }

如果您真的担心将选项值设置为与 key 属性 相同的选项值,则需要使用 track by。即

  ng-options="option.value for option in animals track by option.key">

旁注:不要将 ng-init 与 ng-options 一起使用。

来自文档:

The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.

Angular 1.x 中的 ngOptions 当前不支持排序对象属性。

https://github.com/angular/angular.js/issues/1286

但是,您可以应用下面链接的自定义 toArray 过滤器将对象转换为数组,然后在 orderBy 过滤器之后链接 toArray 转换过滤器:

http://ngmodules.org/modules/angular-toArrayFilter

item in items | toArray | orderBy: 'date'