8

Inside my AngularJS app I have a view with a JQuery datatable, controller to manage data loaded in the datatable as shown below. When refreshing the view, data is loaded without a problem in the datatable, but if I change route to another view then returned back to the view with datatable I get message (No data available in table)...after tracing the issue I found that this happens because the datatable is loaded before the $http call returns. I've tried adding naif on the div containing the datatable to prevent showing it unless there is data returned but no luck as it worked only first time I load the page (by refresh) but wouldn't work on route change. Can someone please tell me what exactly I am doing wrong here and how to resolve this issue? Thanks

app.js

 $stateProvider.state('app.allmembers', {
            url: '/members/members-list',
            templateUrl: 'tpl/members/membersList.html'
 })

Controller.js

 .controller('MembersListController', ['$scope', '$http', 'GlobalService', function($scope, $http, GlobalService) {

      $scope.dset = []; 

      $scope.getMembersList = function() {

        var memURL = 'http://localhost:3000/apiserv/members/';

        $http({ method:'GET',
                url: memURL,
                headers: { 'Content-Type' : 'application/json'
                }                  
             })
        .success(function(data,status,headers,config){
              $scope.dset = data;

              $scope.tbOptions = {
                                  data: $scope.dset,
                                  aoColumns: [
                                    { mData: 'title' },
                                    { mData: 'firstName' },
                                    { mData: 'lastName' },
                                    { mData: 'email' }                          
                                  ],
                                  aoColumnDefs: [  
                                     {
                                       aTargets: [ 3 ],
                                       mRender: function ( data, type, full ) {
                                         return '<a href="mailto:' + data + '" style=color:red;>' + data + '</a>';
                                       }                               
                                     },
                                     {
                                       aTargets: [ 1 ],
                                       mRender: function ( data, type, full ) {
                                         return '<a href="#/app/members/update-member/' + full._id + '" style=color:blue;>' + data + '</a>';
                                       }                               
                                     }
                                  ]                      
              };

              console.log(data);
            }
        }).error(function(data,status,headers,config){
            console.log(status);
        });



      };

  }]) 

membersList.html

<div class="wrapper-md" ng-controller="MembersListController" ng-init="getMembersList()">
  <div class="row">
    <div class="col-sm-10">
      <div class="panel panel-default">
        <div class="panel-body">
                <div class="table-responsive">
                  <table ui-jq="dataTable" ui-options="tbOptions" class="table table-striped m-b-none">
                    <thead>
                      <tr>
                        <th  style="width:15%">Title</th>
                        <th  style="width:30%">First Name</th>
                        <th  style="width:30%">Last Name</th>
                        <th  style="width:25%">Email</th>
                      </tr>
                    </thead>
                    <tbody>
                    </tbody>
                  </table>
                </div>
        </div>
      </div>
    </div>
  </div>
</div>
8
  • I dont see where you are showing the "No data available in table" message. Also would you please put your ng-if statement in the code sample? Commented Nov 18, 2014 at 23:41
  • 2
    You can use a promise to be sure your data is ready before displaying your datatable, or use a resolve into your app route. Commented Nov 19, 2014 at 11:41
  • @Aidin I am not showing the message "No data available in table" this is part of datatables, placed the ng-if before and still it didn't work Commented Nov 19, 2014 at 15:13
  • @senayar can you please give me an example on how to call a controller function upon route loading? thanks Commented Nov 19, 2014 at 15:15
  • Create a factory with your http call and use it into your resolve routing. gist.github.com/senayar/d2e2b09fdf475088a71d And so you can inject directly memberData into your controller. I will help you more tonight if I got time Commented Nov 19, 2014 at 15:39

4 Answers 4

3
+25

You can use Angular directive for Jquery Datatable instead of using other options. It will be good for adding features in Angular way.

URL: http://l-lin.github.io/angular-datatables/

Please check the following example which will help you to complete your task.

URL: http://l-lin.github.io/angular-datatables/#/withAjax

Also, please check the following API for matching your configurations

URL: http://l-lin.github.io/angular-datatables/#/api

Working Demo: http://plnkr.co/edit/fxkaowyvkyIgRNAgcClI?p=preview

Note: The above demo combined with ui-router module. So I believe it will solve your problem.

Sign up to request clarification or add additional context in comments.

1 Comment

this directive for datatable have better solution for loading data: l-lin.github.io/angular-datatables/#/withPromise
0

Setup tbOptions first, and set data object on success:

.controller('MembersListController', ['$scope', '$http', 'GlobalService', function ($scope, $http, GlobalService) {
    $scope.tbOptions = {
        data: [],
        aoColumns: [
          { mData: 'title' },
          { mData: 'firstName' },
          { mData: 'lastName' },
          { mData: 'email' }
        ],
        aoColumnDefs: [
           {
               aTargets: [3],
               mRender: function (data, type, full) {
                   return '<a href="mailto:' + data + '" style=color:red;>' + data + '</a>';
               }
           },
           {
               aTargets: [1],
               mRender: function (data, type, full) {
                   return '<a href="#/app/members/update-member/' + full._id + '" style=color:blue;>' + data + '</a>';
               }
           }
        ]
    };

    $scope.getMembersList = function () {
        var memURL = 'http://localhost:3000/apiserv/members/';
        $http({
            method: 'GET',
            url: memURL,
            headers: {
                'Content-Type': 'application/json'
            }
        })
        .success(function (data, status, headers, config) {
            $scope.tbOptions.data = data;
            console.log(data);
        }).error(function (data, status, headers, config) {
            console.log(status);
        });
    };
    $scope.getMembersList();
}])

Also, avoid ng-init. Initialize inside constructor function. So remove ng-init from your HTML.

1 Comment

Unfortunately I've tried this before and it will work only on first time view being loaded, if you try to change route to another page then get back to the page with the datatable it will again show no data
0

I would prefer you using ngTableParams. Have a look at this. Table Params

app.controller('MembersListController', ['$scope', '$http', 'GlobalService',function($scope,$http, GlobalService,ngTableParams) {

  data = []; 
  $scope.tableParams = new ngTableParams({
    page: 1,
    count: 10,
    sorting: {
        name: 'asc'     // initial sorting
    }
}, {
    counts: [],
    getData: function ($defer, params) {
        var orderedData = params.sorting() ? $filter('orderBy')(data, params.orderBy()) : data;
        var searchedData = searchData(orderedData);
        params.total(searchedData.length);
        $scope.events = searchedData.slice((params.page() - 1) * params.count(), params.page() * params.count());
        if (params.total() < (params.page() - 1) * params.count())   params.page(1);
        $defer.resolve($scope.events);
    },
    $scope: { $data: {} }
});

var searchData = function (orderedData) {
    orderedData = $filter('filter')(orderedData);
    if ($scope.searchText)
        return $filter('filter')(orderedData, $scope.searchText);
    return orderedData
};
  $scope.getMembersList = function() {

    var memURL = 'http://localhost:3000/apiserv/members/';

    $http({ method:'GET',
            url: memURL,
            headers: { 'Content-Type' : 'application/json'
            }                  
         })
    .success(function(data,status,headers,config){
          data = data; // This assigns the data into the array can be accessed through $data in page

          //$scope.tbOptions = {
          //                    data: $scope.dset,
          //                    aoColumns: [
          //                      { mData: 'title' },
          //                      { mData: 'firstName' },
          //                      { mData: 'lastName' },
          //                      { mData: 'email' }                          
          //                    ],
          //                    aoColumnDefs: [  
          //                       {
          //                         aTargets: [ 3 ],
          //                         mRender: function ( data, type, full ) {
          //                           return '<a href="mailto:' + data + '" style=color:red;>' + data + '</a>';
          //                         }                               
          //                       },
          //                       {
          //                         aTargets: [ 1 ],
          //                         mRender: function ( data, type, full ) {
          //                           return '<a href="#/app/members/update-member/' + full._id + '" style=color:blue;>' + data + '</a>';
          //                         }                               
          //                       }
          //                    ]                      
          //};

          console.log(data);
        }
    }).error(function(data,status,headers,config){
        console.log(status);
    });



  };

  }]) 

membersList.html

<div class="wrapper-md" ng-controller="MembersListController" ng-init="getMembersList()">
  <div class="row">
<div class="col-sm-10">
  <div class="panel panel-default">
    <div class="panel-body">
            <div class="table-responsive">
              <table ui-jq="dataTable" class="table table-striped m-b-none">
                <thead>
                  <tr>
                    <th  style="width:15%">Title</th>
                    <th  style="width:30%">First Name</th>
                    <th  style="width:30%">Last Name</th>
                    <th  style="width:25%">Email</th>
                  </tr>
                </thead>
                <tbody>
                  <tr ng-repeat="data in $data">
                  <td>{{data.title}}</td>
                  <td>{{data.firstName}}</td>
                  <td>{{data.lastName}}</td>
                  <td>{{data.email}}</td>
                 </tr>
                </tbody>
              </table>
            </div>
    </div>
  </div>
</div>

The ngTableParams used in .js page is done with order by filter, search data in case of a search bar is available to search the data. The tableParams is reloaded everytime in order to get the list of data.

In the Page the $data is used to access the data present in the tableParams variable in the scope. ngTableParams loads much faster. Hope this helps

Comments

0

MemberService.js

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

MemberService.factory('MemberFactory', ['$q', '$http', function ($q, $http) {
  var memURL = 'http://localhost:3000/apiserv/members/';
  return {
    getMembers: function () {
      var deferred = $q.defer();
      $http({
        method: 'GET',
        url: memURL,
        headers: {'Content-Type': 'application/json'}
      }).success(function (data, status, headers, config) {
        console.log(data);
        deferred.resolve(data);
      }).error(function (data, status, headers, config) {
        deferred.reject(status);
      });
      return deferred.promise;
    }
  };
}]);

app.js (don't forget to include MemberService module into your app dependency)

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

$stateProvider.state('app.allmembers', {
  url: '/members/members-list',
  templateUrl: 'tpl/members/membersList.html',
  resolve: {
    membersData: ['MemberFactory', function(MemberFactory {
      return MemberFactory.getMembers();
    }
  }
})

memberListCtrl.js

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

MembersList.controller('MembersListController', ['$scope', 'GlobalService', 'membersData' function ($scope, GlobalService, membersData) {

  $scope.tbOptions = {
    data: membersData,
    aoColumns: [
      {mData: 'title'},
      {mData: 'firstName'},
      {mData: 'lastName'},
      {mData: 'email'}
    ],
    aoColumnDefs: [
      {
        aTargets: [3],
        mRender: function (data, type, full) {
          return '<a href="mailto:' + data + '" style=color:red;>' + data + '</a>';
        }
      },
      {
        aTargets: [1],
        mRender: function (data, type, full) {
          return '<a href="#/app/members/update-member/' + full._id + '" style=color:blue;>' + data + '</a>';
        }
      }
    ]
  };
}]);

here the gist : https://gist.github.com/senayar/d2e2b09fdf475088a71d

If you still have trouble show your Service and Controller.

4 Comments

I've posted my code on plnkr.co/edit/N8DdNoJYBvn2vv7i2ggA it is the same exact code you are using, except that now even before implementing the controller code I am getting error: Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to: Error: [$injector:nomod] Module 'app' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument. Any thoughts what I might be missing here? Thanks
your plnkr is not usable. Angular is not loaded, and you had includes all your libraries but not added their files. Also declare your components by module. Ex : var MembersList = angular.module('MembersList', []); so you can write MembersList.controller('MembersListController', []); and now add your module in your App.js. I updated the answer to help you
I am sorry but I am a bit confused, just to confirm I got you right, so I shall add MemberService to the app dependancies in app.js even though app.services is already included as a dependency...correct?
Well I don't know, how your module is declared into your application. You need to add your Module Service into your app.js because you want to use the service for the resolve. And if you use a module to declare your controller you also need to add it into your app.js

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.