Abhijit Sarkar Abhijit Sarkar - 4 months ago 111
AngularJS Question

How to Redraw Tables using Angular UI Tabs and UI Grid?

I'm trying to migrate from jQuery Data Tables to Angular UI. My app uses the MySQL World schema and displays the data in 3 different tables. In jQuery, I'd 3 different pages, each launched from a home page. Here's a live example.
In Angular, I created 3 tabs, clicking on each of which is supposed to reload the page with a new grid and populate it with data. Problem is, the grid gets displayed alright on page load with the content on the first tab. On clicking the other tabs, page goes empty and nothing is rendered. Now the data returned is not insignificant, sometimes around 4k rows. However, the problem isn't a latency issue as I've confirmed by waiting several minutes.

I'm not a JS/CSS/HTML guy so most likely I'm missing something. That's why this question.

Edit:
Plnkr URL: http://plnkr.co/edit/6VKTDbfQgdg9l94vFPfo?p=info

Following is the code:

HTML:

<body>
<div id="selection-panel" class="selection-panel" ng-controller="HelloWorldCtrl">
<div>
<uib-tabset type="pills" justified="true">
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" select="update(tab.title)">
<div id="data-panel" class="data-panel" ui-grid="gridOptions"></div>
</uib-tab>
</uib-tabset>
</div>
</div>
<script src="js/app.js"></script>
</body>


JS:

(function() {
var app = angular.module('helloWorld', ['ui.bootstrap', 'ui.grid']);

app.controller('HelloWorldCtrl', ['$http', '$scope', function ($http, $scope) {
$scope.tabs = [
{ title: 'Countries' },
{ title: 'Cities' },
{ title: 'Languages' }
];

$scope.gridOptions = {};
$scope.gridOptions.data = [];

$scope.gridOptionsCountries = {
columnDefs: [
{ name: 'code'},
{ name: 'name'},
{ name: 'continent'},
{ name: 'region'},
{ name: 'population'}
]
};

$scope.gridOptionsCities = {
columnDefs: [
{ name: 'id'},
{ name: 'name'},
{ name: 'country'},
{ name: 'population'}
]
};

$scope.gridOptionsLanguages = {
columnDefs: [
{ name: 'country'},
{ name: 'language'}
]
};

$scope.update = function(title) {
if (title === "Countries") {
$scope.gridOptions = angular.copy($scope.gridOptionsCountries);
} else if (title === "Cities") {
$scope.gridOptions = angular.copy($scope.gridOptionsCities);
} else if (title === "Languages") {
$scope.gridOptions = angular.copy($scope.gridOptionsLanguages);
}

$http.get(title.toLowerCase()).success(function(data) {
$scope.gridOptions.data = data;
});
};
}]);
})();

Answer

I see 2 problems here:

  1. You are creating/changing gridOptions dinamically. This is not the usual way of doing things and can bring many problems.

  2. You are using grids inside of uib-tabs and this, like uib-modals, can have some annoying side effects.

I'd suggest you to address the first issue using different gridOptions (as you do when you create them) and then putting them inside your tabs array children, this way you can refer them from the html this whay:

<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" select="update(tab.title)">
  <div id="data-panel" class="data-panel" ui-grid="tab.gridOptions"></div>
</uib-tab>

The second problem is quite known and inside this tutorial they explain how to address it: you should add a $interval instruction to refresh the grid for some time after it's updated in order to let the tab take its time to load and render.

The code should be as follows:

$scope.tabs[0].gridOptions.data = data; 
$interval( function() {
  $scope.gridCountriesApi.core.handleWindowResize();
}, 10, 500);

Where gridCountriesApi are created inside of a regular onRegisterApi method.

I edited your plunkr, so you can see the whole code.

Comments