Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS ng-table cannot set property '$data' of null

I've just started using ng-table and I'm trying to test it through jasmine unit tests (not sure if this is the best way to test my controllers) and I keep running into this error;

TypeError: Cannot set property '$data' of null
    at project/vendor/assets/javascripts/ng-table-0.3.1/ng-table.src.js:396:55
    at C (project/vendor/assets/javascripts/angular-min.js:92:375)
    at project/vendor/assets/javascripts/angular-min.js:94:28
    at h.$eval (project/vendor/assets/javascripts/angular-min.js:102:308)
    at h.$digest (project/vendor/assets/javascripts/angular-min.js:100:50)
    at h.$apply (project/vendor/assets/javascripts/angular-min.js:103:100)
    at f (project/vendor/assets/javascripts/angular-min.js:67:98)
    at handleResponse (project/vendor/assets/javascripts/angular-mocks.js:1160:9)
    at Function.$httpBackend.flush (project/vendor/assets/javascripts/angular-mocks.js:1491:26)
    at null.<anonymous> (project/spec/javascripts/unit/debtors_controller_spec.js.js:50:24)

Here is where I setup the ngTableParams in my controller

  # Setup ng-table with defaults and data
  $scope.tableParams = new ngTableParams({
    page: 1,
    count: 10,
    sorting: { code: 'asc'}
  }, {
    # data is created by ngTableParams
    total: 0,

    # ng-table will ask for updated data, this is where it gets it from.
    getData: ($defer, params) ->
      # Go get a list of debtors
      Debtor.query {}, (data) ->
        # Once successfully returned from the server with my data process it.
        params.total(data.length)

        # Filter
        filteredData = (if params.filter then $filter('filter')(data, params.filter()) else data)

        # Sort
        orderedData = (if params.sorting then $filter('orderBy')(filteredData, params.orderBy()) else data)

        # Paginate
        $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()))
  })

Here is the jasmine test

  # ================================================================================
  # Delete tests
  # ================================================================================
  describe "destroy", ->
    beforeEach(inject ( ($controller, $rootScope, $location, $state, $httpBackend) ->
      ctrl = $controller('DebtorsController', {
        $scope: @scope,
        $location: $location
      })
    ))

    it "gets new listing", ->
      @scope.debtors = [{id: 1, name: "Good guys"}, {id: 2, name: "John"}]
      @httpBackend.whenDELETE('/clients/1').respond(200)
      @httpBackend.whenGET('/debtors').respond(200,  [{name: "John"}])
      @scope.destroy(1)
      @httpBackend.flush()
      expect(@scope.debtors[0].name).toEqual('John')

Here is my code for deleting (which works)

  # --------------------------------------------------------------------------------
  # Delete
  # --------------------------------------------------------------------------------
  $scope.destroy = (id) ->
    Client.delete
      id: id
    , (response) ->             # Success
      flash("notice", "Client deleted", 2000)
      $scope.tableParams.reload() # Reload ng-table data, which will get a new listing from the server.
    , (response) ->             # Failure
like image 996
map7 Avatar asked Feb 13 '14 05:02

map7


1 Answers

Can you show the code in your controller where you initialize ngTableParams?

Problem is ng-table uses ngTableController to set the $scope for ngTableParams. Since you are unit testing you wont have a ngTableController so $scope of ngTableParams will be null. You should manually set $scope of ngTableParams in your unit test. Try something similar to this JS (really dislike coffeescript, so convert to your needs):

beforeEach(inject(function ($controller, $rootScope) {
            scope = $rootScope.$new();
            ctrl = $controller('DebtorsController', {
                $scope: scope,
                $location: $location
            });
            scope.tableParams.settings().$scope = scope;
        }));

Assuming you have something like the following in your controller where you initialize your ngTableParams:

$scope.tableParams = new ngTableParams({
    page: 1,            // show first page
    count: 10           // count per page
}, {
    total: data.length, // length of data
    getData: function($defer, params) {
        $defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
    }
});
like image 165
Beyers Avatar answered Oct 15 '22 13:10

Beyers