如何使用 Angular UI 选项卡和 UI 网格重绘表格?

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

我正在尝试从 jQuery 数据表迁移到 Angular UI。我的应用程序使用 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。 在 Angular 中,我创建了 3 个选项卡,单击每个选项卡应该会使用新网格重新加载页面并用数据填充它。问题是,网格在第一个选项卡上的内容在页面加载时显示正常。单击其他选项卡时,页面变空并且不呈现任何内容。现在返回的数据不是微不足道的,有时大约 4k 行。但是,正如我通过等待几分钟确认的那样,问题不是延迟问题。

我不是 JS/CSS/HTML 人,所以很可能我遗漏了什么。这就是为什么这个问题。

编辑: Plnkr

代码如下:

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;
            });
        };
    }]);
})();

我无法让它在选项卡中工作,我的猜测是因为你首先使用 ng-repeat 为每次迭代创建一个范围,然后选项卡本身可能创建一个新的范围,这会引起很多麻烦有更新。

最快的解决方案就是将网格移到选项卡之外。

这是更新后的 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>

我在这里看到 2 个问题:

  1. 你是 creating/changing gridOptions 动态的。这不是通常的做事方式,会带来很多问题。

  2. 您正在 uib-tabs 内部使用网格,这与 uib-modals 一样可能会产生一些恼人的副作用。

我建议您使用不同的 gridOptions 来解决第一个问题(就像您创建它们时所做的那样),然后将它们放入您的 tabs 数组子项中,这样您可以参考他们来自 html 这个 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>

第二个问题是众所周知的,在 this 教程中他们解释了如何解决它:您应该添加一个 $interval 指令在网格更新后刷新一段时间,以便让选项卡需要时间来加载和呈现。

代码应该如下:

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

其中 gridCountriesApi 是在常规 onRegisterApi 方法中创建的。

我编辑了你的 plunkr,所以你可以看到完整的代码。

在我的情况下,选项卡内容会占用重要的加载时间。因此,如果您不想在每次单击选项卡时都更新选项卡内容,则可以使用此解决方法:

在 HTML 部分,我使用 select 属性 来指示按下了哪个选项卡:

<tabset justified="true">
    <tab heading="Tab 1" select="setFlag('showTab1')">
        <div ng-if="showTab1">
        ...
        </div>
    </tab>
</tabset>

在选项卡 (*) 容器中,我使用了一个开关来识别按下了哪个选项卡并广播了按下操作:

case 'showTab1':
    $scope.$broadcast('tab1Selected');
    break;

在控制器部分,我监听事件并处理调整大小:

// 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);
});

这是我的 Plunkr。希望对你有帮助。

(*) 对于当前的 bootstrap 版本,您应该使用