如何根据 AngularJS 中的子结果集对结果进行排序

How do I order results based on a child set of results in AngularJS

鉴于我有以下对象:

{
    "bands": [{
        "name": "The Wibbles",
        "formed": 1992,
        "albums": [{
            "name": "A New Wibble",
            "songs": [{
                "name": "Song One",
                "time": "3:12"
            }, {
                "name": "Song Two",
                "time": "2:34"
            }, {
                "name": "Song Three",
                "time": "2:21"
            }, {
                "name": "Song Four",
                "time": "3:44"
            }, {
                "name": "Song Five",
                "time": "3:54"
            }]
        }, {
            "name": "The Wibbles Strike Back",
            "songs": [{
                "name": "Song Six",
                "time": "8:12"
            }, {
                "name": "Song Seven",
                "time": "7:34"
            }, {
                "name": "I Killed a Girl",
                "time": "8:21"
            }, {
                "name": "Monkey Fighters",
                "time": "7:44"
            }, {
                "name": "Funkallica",
                "time": "9:54"
            }]
        }]
    }]
}

使用 AngularJS(可能还有 underscore.js),我如何按最短曲目、专辑总长度或专辑曲目的最短平均长度对专辑进行排序?

如果我要添加另一个乐队,我将如何通过这些过滤器(最短曲目/专辑长度/平均曲目长度)对乐队本身进行排序?

排序数字字符串有点麻烦,但我们仍然可以解决它。这是给出以下 html:

的示例
<div ng-repeat="band in bands">
  <h1>{{ band.name }}</h1>
  <div ng-repeat="album in band.albums">
    <h2>{{ album.name }}</h2>
    <ul>
      <li ng-repeat="songs in album.songs">
        <h3>{{ song.name }}</h3>
        <em>{{ song.time }}</em>
      </li>
  </div>
</div>

现在,要按最短曲目排序专辑:

<div ng-repeat="band in bands">
  <h1>{{ band.name }}</h1>
  <div ng-repeat="album in band.albums | orderBy:shortestTrackByAlbum">
    <h2>{{ album.name }}</h2>
    <ul>
      <li ng-repeat="song in album.songs">
        <h3>{{ song.name }}</h3>
        <em>{{ song.time }}</em>
      </li>
    </ul>
  </div>
</div>

如您所见,为了执行自定义 orderBy,我们需要在将用于 return 正在排序的值;在本例中为“orderBy:shortestTrackByAlbum”。

$scope.bands = [...];
$scope.shortestTrackByAlbum = function(album) {
  var times = [];
  for (var i = 0; i < album.songs.length; i++) {
    var minutesAndSeconds = album.songs[i].split(':'),
        m = parseInt(minutesAndSeconds[0], 10),
        s = parseInt(minutesAndSeconds[1], 10);
    times.push(m * 60 + s);
  }
  return Math.min.apply(null, times);
};

根据你提供的数据,我将你的时间换算成秒,找出曲目中秒数最小的。然后将这个最小的数字与其他专辑的最小的数字进行比较,以对所有这些最小的数字进行排序(请原谅冗余)。

使用此模式,您应该能够为每种情况编写一个函数。请参阅此 Plunker 以获取简单示例。

此外:如果您希望用户能够更改排序,您可以执行如下操作:

<select ng-model="sortingMethod"
        ng-options="m.fn as m.name for m in methods"></select>

...
  <div ng-repeat="album in albums | orderBy:sortingMethod">
...
$scope.methods = [
  {
    name: 'Shortest Track',
    fn: $scope.shortestTrackByAlbum
  },
  {
    name: 'Total Album Length',
    fn: $scope.totalAlbumLengthByAlbum
  },
  {
    name: 'Shortest Average Length',
    fn: $scope.shortestAverageLengthByAlbum
  }
];

$scope.shortestTrackByAlbum = function(album) { ... };
$scope.totalAlbumLengthByAlbum = function(album) { ... };
$scope.shortestAverageLengthByAlbum = function(album) { ... };

一定要查看 Angular Filters and more specifically Angular's OrderBy 上的文档。