Angularjs ng-table with AJAX data source, sorting and filtering

Almaron picture Almaron · Jun 6, 2014 · Viewed 25k times · Source

I'm trying to apply the ngTable directive to my Rails app, but can't get it right. I'm still a newbe in angular and this directive seems very poorly documented (though has a great variety of nice examples).

So I have an array called $scope.users containing all the users info I need (e.g. like this), which comes from a $resource query().

And I need to turn it into a table with:

  1. Sorting
  2. Pagination
  3. Filtering from one input (like done over here)

Can someone provide a solution or at least an advice how to put it all together?

UPDATE

So, with great help of wafflejock on the irc channel I've been able to put together some of the functionality. Here's the plunk.

What is still wrong:

  1. The json dataset gets requested every time I change the page, the sorting or anything else. That's a huge amount of requests, so I need it to get cached somehow.
  2. I need to be able to manipulate the dataset from the controller to change the values and remove users if need be. Still have no idea how to implement that.

Answer

shaunhusain picture shaunhusain · Jun 11, 2014

Hi Almaron (aka Malkav) I'm wafflejock from the IRC here's the thing working as best I could get it:

http://plnkr.co/edit/TUOYmM?p=preview

var app = angular.module('main', ['ngTable']).
controller('DemoCtrl', function($scope, ngTableParams, NameService) {

    var data = NameService.data;

    $scope.tableParams = new ngTableParams(
      {
        page: 1,            // show first page
        count: 10,           // count per page
        sorting: {name:'asc'}
      },
      {
        total: 0, // length of data
        getData: function($defer, params) {
          NameService.getData($defer,params,$scope.filter);
        }
    });

    $scope.$watch("filter.$", function () {
        $scope.tableParams.reload();
    });

});

app.service("NameService", function($http, $filter){

  function filterData(data, filter){
    return $filter('filter')(data, filter)
  }

  function orderData(data, params){
    return params.sorting() ? $filter('orderBy')(data, params.orderBy()) : filteredData;
  }

  function sliceData(data, params){
    return data.slice((params.page() - 1) * params.count(), params.page() * params.count())
  }

  function transformData(data,filter,params){
    return sliceData( orderData( filterData(data,filter), params ), params);
  }

  var service = {
    cachedData:[],
    getData:function($defer, params, filter){
      if(service.cachedData.length>0){
        console.log("using cached data")
        var filteredData = filterData(service.cachedData,filter);
        var transformedData = sliceData(orderData(filteredData,params),params);
        params.total(filteredData.length)
        $defer.resolve(transformedData);
      }
      else{
        console.log("fetching data")
        $http.get("http://www.json-generator.com/api/json/get/bUAZFEHxCG").success(function(resp)
        {
          angular.copy(resp,service.cachedData)
          params.total(resp.length)
          var filteredData = $filter('filter')(resp, filter);
          var transformedData = transformData(resp,filter,params)

          $defer.resolve(transformedData);
        });  
      }

    }
  };
  return service;  
});

Basically I setup a few functions to do the those long lines to make it a bit easier to read and then setup a cachedData object that I check to see if it's populated before making the call... it looks like it still makes two calls very quickly at the beginning I'm sure you can avoid this by using a flag to check if the data is being loaded already and if so just have it wait instead of redoing the call but not sure it's a huge deal.