0

How can I approach table sorting in angularjs, when my data is nested and not all columns are first level citizens of the objects.

Data (excerpt)

[
    {
        "name": "Team A",
        "categories": [
            {
                "label": "FG%",
                "value": 4676,
                "points": 7
            },
            {
                "label": "FT%",
                "value": 8387,
                "points": 9
            }
        ]
    }, {
        "name": "Team B",
        "categories": [
            {
                "label": "FG%",
                "value": 5285,
                "points": 10
            },
            {
                "label": "FT%",
                "value": 6111,
                "points": 1
            }
        ]
    }
]

HTML

<div ng-controller="mainCtrl">
    <table class="table table-striped table-condensed">
        <thead>
            <tr>
                <th ng:click="changeSorting('name')">Name</th>
                <th ng:click="changeSorting('name')">Points</th>
                <th ng:click="changeSorting(value.label)" ng-repeat="(index, value) in data.teams[0].categories">{{value.label}}</th>

            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="team in data.teams | orderBy:sort.column:sort.descending ">
                <td>{{team.name}}</td>
                <td>{{team.totalPoints}}</td>
                <td ng-repeat="(name, cat) in team.categories">
                    {{cat.value}}
                </td>
            </tr>
        </tbody>
    </table>
</div>

Here is a approach I found a few times. Anyway, because of the structure of my data, I am afraid this isn't the right idea.

Sorting on Controller

$scope.sort = {
    column: 'name',
    descending: false
};

$scope.changeSorting = function(column) {
    var sort = $scope.sort;
    if (sort.column == column) {
        sort.descending = !sort.descending;
    } else {
        sort.column = column;
        sort.descending = false;
    }
};

Here is the updated fiddle: http://jsfiddle.net/SunnyRed/mTywq/2/

2
  • Where is the table sorting? Also, have you looked at ng-grid as a ready-made-solution? Commented Nov 16, 2013 at 15:28
  • There was none, because I don't know of any approach. I still have added a common way for table-sorting, but that only works for the first level citizens. I did have a look at ng-grid, but I had the impression, that nested data isn't featured. Commented Nov 16, 2013 at 16:18

2 Answers 2

3

I modified your code based on angular documentation at http://docs.angularjs.org/api/ng.filter:orderBy

HTML

<div ng-controller="mainCtrl">

    <table class="table table-striped table-condensed">
        <thead>
            <tr>
                <th ng:click="predicate = 'name'; reverse = !reverse">Name</th>
                <th ng:click="predicate = 'totalPoints'; reverse = !reverse">Points</th>
                <th ng:click="toggleSort($index)" ng-repeat="category in data.teams[0].categories">{{category.label}}</th>
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="team in data.teams | orderBy:predicate:reverse">
                <td>{{team.name}}</td>
                <td>{{team.totalPoints}}</td>
                <td ng-repeat="(name, cat) in team.categories">
                    {{cat.value}}
                </td>                    
            </tr>
        </tbody>
    </table>
</div>

Sorting parts

$scope.toggleSort = function(index){
    $scope.reverse = !$scope.reverse;
    $scope.predicate = function(team){
        return team.categories[index].points;
    }
}

Here is the fiddle: http://jsfiddle.net/mgalela/Br5Wb/14/

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. That was exactly, what I was looking for. I've also added a variable on the scope, to remember sorting and so reverse sorting only when the same header is clicked again and otherwise set the default. Nevertheless, many thanks :)
1

Since you need to lookup the correct category based on it's label and then sort using it's associated value I'd create a custom orderBy function.

To use new function sortFunc we add it here:

<tr ng-repeat="team in data.teams | orderBy: sortFunc ">

Then let the user pick options:

<select ng-model="sortVal">
    <option value="name">Name</option>
    <option value="points">points</option>
    <option value="3PM">3PM</option>
    <option value="PTS">PTS</option>
 </select>

Finally here's the sort function which pulls in the chosen option using $scope.sortVal and returns the appropriate value for orderBy to sort.

$scope.sortFunc = function(val) {
    if ($scope.sortVal == 'name') {
         return(val.name);
     } else if ($scope.sortVal == 'points') {
         return(val.totalPoints);
     } else if ($scope.sortVal == '3PM' ||
                $scope.sortVal == 'PTS')  {  
         for (var i = 0; i < val.categories.length; i++) {
            category = val.categories[i];
            if (category.label == $scope.sortVal){
               return(category.value);
            }
         }
    }
}

Here's the fiddle of this working: http://jsfiddle.net/mTywq/4/

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.