Tantelope
Tantelope

Reputation: 617

AngularJS - How to order ng-repeat using another array

Say I have an array of keys in a specific order

orderedNames=["mike","bob","sarah];

and I have a JSON that I want to show using ng-repeat but in the order that they appear in the array:

{"people":
    {
    "bob":{
        "hair":"brown",
        "eyes":"blue",
        "height":"tall"
        },
    "sarah":{
        "hair":"blonde",
        "eyes":"blue",
        "height":"short"
        }, 
    "mike":{
        "hair":"red",
        "eyes":"blue",
        "height":"tall"
        }
    }
}

How do I write a filer that would cause ng-repeat to spit out the people in the order in which they are specified in the array?

<li ng-repeat="person in people | orderNames"></li>

Upvotes: 1

Views: 1836

Answers (4)

Clint
Clint

Reputation: 1073

to ng-repeat order by another array use

in the controller

$scope.somearray = [1,2,3,4] //or what ever you want to sort by

in the template.

| orderByArray:somearray:true/false

the true/false setting determines if stuff that isn't in the sortby array is outputted after the stuff that is or just dropped.

add the filter

var app = angular.module("app", []).filter("orderByArray", function () {
            return function (input, sortBy, includeOrphans) {
                //sorts by array and returns items with unsorted items at the end if they are not in the sortby array
                if (!angular.isDefined(input)) { return; }
                var ordered = [];
                var remainder = _.cloneDeep(input);
                angular.forEach(sortBy, function (sortitem) {
                    if (angular.isDefined(input[sortitem])) {
                        ordered.push(input[sortitem]);
                        delete (remainder[sortitem]);
                    }
                });
                if (includeOrphans) {
                    angular.forEach(remainder, function (remainingItem, key) {
                        ordered.push(input[key]);
                    });
                }
                return ordered;
            };
        });

Upvotes: 0

You can define a custom filter.

Plunker: http://plnkr.co/edit/fiuuGoGZK7tM5oefKQlS

index.html

<!DOCTYPE html>
<html ng-app="plunker">

<head>
    <meta charset="utf-8" />
    <title>Filter Example</title>
    <link rel="stylesheet" href="style.css" />
    <script data-require="[email protected]" src="http://code.angularjs.org/1.2.15/angular.js" data-semver="1.2.15"></script>
    <script src="app.js"></script>
</head>

<body ng-controller="MainCtrl">
<li ng-repeat="person in people|orderNames:orderedNames track by $index">{{person.hair}}</li>
</body>

</html>

app.js:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
    $scope.people={
        bob:{
            hair:"brown",
            eyes:"blue",
            height:"tall"
        },
        sarah:{
            hair:"blonde",
            eyes:"blue",
            height:"short"
        },
        mike:{
            hair:"red",
            eyes:"blue",
            height:"tall"
        }
    };
    $scope.orderedNames=["mike","bob","sarah"];

});

app.filter("orderNames",function(){
    return function(input,sortBy) {
        var ordered = [];
        for (var key in sortBy) {
            ordered.push(input[sortBy[key]]);
        }

        return ordered;
    };
});

Upvotes: 4

a8m
a8m

Reputation: 9474

use array as a reference :

http://jsbin.com/jujoj/14/edit

    $scope.persons = {
   bob:{
     name:'bob'
   },
   mike:{
     name: 'mike'
   },
   sarah: {
     name: 'sarah'
   }
 };

 $scope.orderedNames = [$scope.persons.mike, $scope.persons.bob, $scope.persons.sarah];

HTML : <ul ng-repeat="person in orderedNames"> <li>{{ person.name }}</li> </ul>

Upvotes: 1

zs2020
zs2020

Reputation: 54524

You could try something like this

<li ng-repeat="name in orderNames">
    {{people[name]}}
</li>

Upvotes: 4

Related Questions