0

my nested json is killing me, seem I have to write a custom filter to do orderBy

$scope.ranking = [

    {
        'uId': 2,
            'name': 'Jeremy',
            'tabs': [{
            'tabId': 1,
                'points': 100,
        }, {
            'tabId': 2,
                'points': 10
        }],

    },

    {
        'uId': 3,
            'name': 'Jordon',
            'tabs': [{
            'tabId': 1,
                'points': 180,
            },{
            'tabId': 2,
                'points': 5
        }],
    }]


}

what I want is sort users' ranking by points. It would be easy if the tabs contain single points, but multiple tabs indicate the types of game they played.

look at my fiddle then you'll know what I'm try to do, here http://jsfiddle.net/U4dd8/

I wrote my custom filter until here

app.filter("rankFilter", function(){
   return function (input, points) {
       var output = [];      

           for (var i in input) {

       for(var j in input[i].tabs){
        var points = input[i].tabs[j].points;

        output.push(points);

        }

       }   

    return output;
};
2
  • 1
    I'm not sure I understood correctly. Are you trying to display the total points for each user and sort users according to total points? Commented Apr 19, 2014 at 8:08
  • sort user base on user point Commented Apr 19, 2014 at 9:06

2 Answers 2

1

If I understand correctly you want to display in each tab the users that have points for that category and sort them by points (for that specific category).

It's a very localized question (and rather not Angular-related), but here is a possible solution:

HTML:

<li ng-repeat="user in ranking | orderByPointsForTab:currentTab">
    <a ng-click="showFriendsTasksEvent(user.uId)">
        {{user.name}} {{user.tabs | pointsForTab:currentTab}}
    </a>
</li>

2 filters are used:

  1. pointsForTab: It takes a tabs array and the currentTab as arguments and returns the points associated with the current tab.
    This could as well be a function in the controller.

  2. orderByPointsForTab: It takes a users array and currentTab as arguments and returns an new array containing only the users that have points for the current tab and sorted in descending order of points (for the current tab).

In order to understand the code below, you should be familiar with the following methods of Array (standard JS - nothing Angular-specific):
- Array.prorotype.forEach
- Array.prorotype.some
- Array.prorotype.map
- Array.prorotype.sort

app.filter("orderByPointsForTab", function () {

    /* `users` and `currentTab` as input */
    return function (users, currentTab) {

        /* 1: Create an array of users that have points
         *    for current tab (in random order) */
        var unsortedUsersWithPoints = [];
        (users || []).forEach(function (user) {

            /* Iterate over the tabs of each user... */
            (user.tabs || []).some(function (tab) {

                /* ...until we find the current tab... */
                if (tab.tabId === currentTab) {

                    /* ...store the user and the points for current tab
                     * for later access (see below)... */
                    unsortedUsersWithPoints.push({
                        user: user,
                        points: tab.points
                    });

                    /* ...and break the loop for the current user */
                    return true;
                }
            });
        });

        /* 2: Sort the array of `{user, points}` objects 
         *    in descending order of points */
        var sortedUsersWithPoints = unsortedUsersWithPoints.sort(
            function (obj1, obj2) {
                return obj2.points - obj1.points;
            }
        );

        /* 3: Create a new array containing only `user` objects,
         *    but keeping the order in `sortedUsersWithPoints` (see above) */
        var output = sortedUsersWithPoints.map(function (obj) {
            return obj.user;
        });

        /* 4. Return the sorted `users` array */
        return output;
    };
});

The code described above can be found in this short demo.

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

Comments

0

First, since you already have currentTab in the view, you could select the users to display for each tab using ng-show instead of using extra filters. Then, use a custom filter (orderByPoints) to implement a custom sort that orders the users according to tab points.

Your view becomes

<div ng-controller="AppCtrl">
    <button ng-click="currentTab=1">shooting</button>
    <button ng-click="currentTab=2">dribble</button>
    <p>Leaderboard</p>
    <ul>
        <li ng-repeat="user in ranking | orderByPoints: currentTab"> 
            <span ng-repeat="tab in user.tabs">
                <span ng-show="tab.tabId == currentTab">
                    <a ng-click="showFriendsTasksEvent(user.uId)">
                        {{ user.name }} - {{ tab.points }}
                    </a>
                </span>
            </span>
        </li>
    </ul>
</div>

Custom filter

app.filter("orderByPoints", function () {
    var inputTab;
    function compare(a, b) {
        // Check for undefined since value may be missing for some users
        if (typeof a.tabs[inputTab] != 'undefined' && typeof b.tabs[inputTab] != 'undefined')
            return b.tabs[inputTab].points - a.tabs[inputTab].points;
        return 0;
    }
    // Filter function
    return function (input, currentTab) {
        inputTab = currentTab; // Get current tab
        return input.sort(compare); // Call custom sort
    }
});

Here is an updated Fiddle (I added an extra user and tab for demonstration).

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.