问题
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
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;
});
};
}]);
})();
回答1:
I see 2 problems here:
You are creating/changing
gridOptions
dinamically. This is not the usual way of doing things and can bring many problems.You are using grids inside of
uib-tabs
and this, likeuib-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.
回答2:
I can not get this to work in tabs, my guess is because you first use ng-repeat which creates a scope for each iteration, and then maybe the tabs itself creates a new scope and this causes a lot of headache with updates.
The quickest solution is just to move the grid outside of the tabs.
Here is the updated html.
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>
</uib-tab>
</uib-tabset>
<!-- This is moved outside -->
<div id="data-panel" class="data-panel" ui-grid="gridOptions">
</div>
</div>
<script src="js/app.js"></script>
</body>
回答3:
In my situation tab contents consume important time to be loaded. So if your case is that you don't want to update tab content everytime the tab is clicked, you can use this workaround:
In the HTML part I use select property to indicate which tab is pressed:
<tabset justified="true">
<tab heading="Tab 1" select="setFlag('showTab1')">
<div ng-if="showTab1">
...
</div>
</tab>
</tabset>
In the tab (*) container I used a switch to recognize which tab is pressed and broadcast the press action:
case 'showTab1':
$scope.$broadcast('tab1Selected');
break;
And in the controller part I listen the event and handle resizing:
// The timeout 0 function ensures that the code is run zero milliseconds after angular has finished processing the document.
$scope.$on('tab1Selected', function () {
$timeout(function() {
$scope.gridApi1.core.handleWindowResize();
}, 0);
});
Here is my Plunkr. Hope it helps.
(*) For current bootstrap version you should use and
来源:https://stackoverflow.com/questions/34261631/how-to-redraw-tables-using-angular-ui-tabs-and-ui-grid