user2402107 user2402107 - 4 months ago 23
Javascript Question

Using a Custom Filter in AngularJs

I am relatively new to AngularJs and I came across a problem when using OrderBy: in regards to sorting objects, so I borrowed a custom filter to sort objects but I am not understanding what the correct syntax to use this Filter appropriately as it wont sort by the Key in the object I want it to:

js:

<tbody ng-repeat="(field, profile) in currentSample.dsProfile | orderByObject:'profile[display-name]' track by $index">
<tr ng-style="$index % 2 === 0 && {'background-color': '#ffffff'} ||
$index % 2 === 1 && {'background-color': '#f9f9f9'}">
<td style="width: 19%; margin: 2px; padding: 0px;"
ng-style="profile['shown-in-details'] == true && {'background-color': 'gold'} ||
profile['shown-in-details'] == false && {'background-color': 'transparent'}">
<span class="btn-property"
ng-click="showInGenericDetails(currentSample, field)"
uib-tooltip="{{field}}"
tooltip-placement="right">
<b>{{profile["display-name"]}}</b>
</span>


jsonenter image description here

Filter:

app.filter('orderByObject', function() {
return function(items, field, reverse) {
var filtered = [];
angular.forEach(items, function(item) {
filtered.push(item);
});
filtered.sort(function (a, b) {
return (a[field] > b[field] ? 1 : -1);
});
if(reverse) filtered.reverse();
return filtered;
};
});


without filter

<table id="data-sources-table" class="table drag-drop">
<tbody ng-repeat="(field, profile) in currentSchema.sProfile | orderBy:PROPERTY track by $index">
<tr ng-style="$index %2 === 0 && {'background-color': '#ffffff'} ||
$index %2 === 1 && {'background-color': '#f9f9f9'}">
<td style="width: 180px">
<span class="btn-property">
<b>{{field}}</b>

Answer

Since you can't use orderBy directly because this filter needs to filter a collection, you should parse your items to a collection, something like this:

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

app.controller('mainCtrl', function($scope) {
  var testObj = {  
     "obj1":{  
        "id":1,
        "title":"Title1"
     },
     "obj2":{  
        "id":2,
        "title":"Title2"
     },
     "obj3":{  
        "id":3,
        "title":"Title3"
     }
  }; 

  $scope.testArray = [];
  Object.keys(testObj).forEach(function(key) {
    $scope.testArray.push(testObj[key]);
  });
  // Now you can use $scope.testArray as a normal array in your view.
});
<!DOCTYPE html>
<html ng-app="app">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
</head>

<body ng-controller="mainCtrl">
  <ul>
    <li ng-repeat="obj in testArray | orderBy: title: reverse" ng-bind="obj.title"></li>
  </ul>
  <button type="button" ng-model="reverse" ng-click="reverse = !reverse">Reverse order</button>
</body>

</html>

Note: Doing this way, you just need to parse your objects to array once, instead of doing this everytime when needs to sort.

Reference: https://docs.angularjs.org/error/orderBy/notarray

I hope it helps!

EDIT:

I noticed you're using this construction:

ng-style="$index % 2 === 0 && {'background-color': '#ffffff'} || $index % 2 === 1 && {'background-color': '#f9f9f9'}"

You can simplify your life simply using the native special-properties, then you can have something like this:

ng-style="$even && {'background-color': '#ffffff'} || $odd && {'background-color': '#f9f9f9'}"

Note: Change your ng-repeat to your <tr> tag.