如何根据AngularJS中的子结果集来订购结果

时间:2015-02-20 16:07:35

标签: javascript angularjs underscore.js

鉴于我有以下对象:

{
    "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),我如何按最短曲目,专辑总长度或专辑曲目的最短平均长度订购专辑?

如果我要添加另一个乐队,我将如何通过这些过滤器(最短曲目/专辑长度/平均曲目长度)自行订购乐队?

1 个答案:

答案 0 :(得分:2)

排序数字字符串是一种痛苦,但我们仍然可以解决它。这是一个给出以下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,我们需要在当前Scope上传递函数(不是函数的结果),该函数将用于返回值正在分类;在这种情况下`orderBy:shortestTrackByAlbum&#39;。

$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上的文档,更具体地说是Angular's OrderBy