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

3

9

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.
Samson answered 6/6, 2014 at 10:27 Comment(0)
E
11

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.

Eggert answered 11/6, 2014 at 4:26 Comment(1)
Thanks a lot. I believe the second call comes from the $watch on the filter. The only question I have here is why is the data loaded from Nameservice.data when there is no such thing there any more?Samson
P
0

The second parameter of $http.get takes a config object - one of the keys it takes is cache, which you can set to true to cache your get request. Another method to reduce requests would be to use _.debounce from lodash or underscore to debounce requests made within a certain time period.

For editing data, in your template, you can have an input with ng-model and a span with a ng-bind (or double curly braces {{ }}) and have an ng-show and ng-hide on the same variable for them for editing.

Photoactinic answered 10/6, 2014 at 11:55 Comment(3)
Thanks, I thought about caching, but what I really want to do is try to get that $http request out of the getData function and put there some kind of $scope.users array that I can manipulate trough the controller.Samson
I would remove the NameService.getData call outside the ngTable class instantiation and just do it elsewhere in the controller, and set the results to $scope.users, then just use that data with ngTable.Photoactinic
Here's a stripped down plnkr: plnkr.co/edit/JM10jH?p=preview Note that I took out your sorting logic and such - you will have to re-implement it, but it should be easier to figure out where you want that logic to live and without being heavily tied to ngTable in the API call.Photoactinic
A
0

Second call can be prevented by simple if condition scope.returnListGrid.settings().$scope!=null

Alinealinna answered 14/8, 2014 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.