Angular JS – ngRepeat with an Object + Custom Filters

We can use the ngRepeat directive to loop over an object’s properties, instead of looping over an array’s items. This can be useful in some circumstances, e.g. when we want to directly refer each element without have to keep in mind indexes. In this example we want to store the tabs of a tabset as properties of an object.

$scope.tabs = {
    Tab1: { order: 1, heading: "Tab 1" },
    Tab2: { order: 4, heading: "Tab 2" },
    Tab3: { order: 2, heading: "Tab 3" },
    Tab4: { order: 3, heading: "Tab 4" },
    Tab5: { order: 5, heading: "Tab 5" }
};

To loop over this object using the ngRepeat directive we can do in this way:

<div class="tabset">
    <tabset>
        <tab ng-repeat="(key, tab) in tabs | orderObjectBy: 'order'">
            {{tab.heading}}
        </tab>
    </tabset>
</div>

The orderBy issue

As we can see from the example we aren’t using the usual orderBy filter. The reason for this is that the property’s order of an object is not as deterministic as the item’s order within an array. The way in which they are stored is strictly connected with the object’s allocation management of each browser. As consequence we’ll often have the properties returned in alphabetical order even if we haven’t specified a particular order. Another consequence is that the classic orderBy filter simply doesn’t work in this situation (probably will be fixed in the future, but this is the current situation). So that’s the reason why we created an orderObjectBy custom filter to manage this.

angular.module('TmyApp.filters').filter("orderObjectBy", function () {
    return function (items, field, reverse) {
        var filtered = [];
        angular.forEach(items, function (item) {
            filtered.push(item);
        });
        for (var n = 0; n < filtered.length - 1; n++) {
            for (var k = n + 1; k < filtered.length; k++) {
                if ((!reverse && filtered[n][field] > filtered[k][field])
                    || (reverse && filtered[n][field] < filtered[k][field])) {
                    var temp = filtered[n];
                    filtered[n] = filtered[k];
                    filtered[k] = temp;
                }
            }
        }
        return filtered;
    };
});
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s