如何使用不同角度控制器重复使用相同的ui-grid

时间:2018-06-15 17:52:10

标签: c# angularjs model-view-controller angular-ui-grid

我是Angular 1.6和UI-grid的新手,所以我正在努力解决一些简单的问题。我希望在我的主控制器中定义一个UI网格,重新定义并重新使用来自不同Angular控制器的数据。更具体地说,我想在主Angular控制器中使用单个网格定义来拥有多个.CSHTML网格模板。我想从不同的Angular控制器填充网格数据数组,具有不同的数据和不同的列定义。一次只能有一个活动网格。

为每个控制器使用单独的网格定义,但我最终可能有20个网格;所以我不想在我的主Angular控制器中那么多可重复的膨胀。网格定义中唯一要更改的部分是列定义和数据。下面是一个简化的项目布局,以帮助讨论。

在我的主要Angular控制器中,我有一个UI网格定义,我想从不同文件中的多个Angular控制器重用它。网格定义如下:

//MainController in app.js
(function () {
    'use strict';

    angular.module('CRNApp', ['ui.bootstrap', 'ui.grid', 'ui.grid.autoResize', 'ui.grid.emptyBaseLayer', 'ui.grid.selection']);

    MainController.$inject = ['$scope', '$http', '$uibModal', '$log','uiGridConstants'];

    angular.module('CRNApp')
    .controller('MainController', MainController);

    $scope.policyList = {                //grid options and data for policy data
        rowHeight: 40,
        enableFiltering: true,
        enableRowSelection: true,
        enableRowHeaderSelection: false,
        data: 'policyData',
        columnDefs: [ //the column defs will be different for each different controller
            { name: 'PolicyId'},
            { name: 'PolicyState'},
            { name: 'AgentName' },
            { name: 'InforcePremium' },
            { name: 'LOB'}
        ]
    };
    $scope.policyData = [];              //stores policy array returned from MVC controller to UI
    $scope.policySelected = 'false';     //tracks if a row is selected. Allows row-depenendent nav buttons to be enabled on bav bar
    $scope.mySelectedPolicy = {};

    //grid options for processor grid
    $scope.policyList.multiSelect = false;
    $scope.policyList.modifierKeysToMultiSelect = false;
    $scope.policyList.noUnselect = false;
    $scope.policyList.onRegisterApi = function (policyApi) {
        $scope.policyApi = policyApi;
        $scope.policyApi.selection.on.rowSelectionChanged($scope, function (row) {
            if (row.isSelected) {
                $scope.policySelected = 'true';
                $scope.mySelectedPolicy = row.entity; //copy selected row so that we can access it from processor controller
            }
            else
                $scope.policySelected = 'false';
        });
    };

    //this function recalculates the height of the visible grid after the row count changes
    $scope.getPolicyTableHeight = function () {
        var rowHeight = 30; // your row height
        var headerHeight = 30; // your header height
        return {
            height: ($scope.policyList.data.length * rowHeight + headerHeight) + "px"
        };
    };

}());

在主_Layout.cshtml中,导航栏上有一个按钮,该按钮绑定到名为“PolicyController”的单独Angular控制器中的函数。该函数的名称称为“loadPoliciesGrid()”。此函数使用数据填充policyList网格定义中的policyData数组(请参阅上面的主控制器)。我将在页面上有多个按钮,在不同的控制器中调用类似的功能。例如,我将有一个Processor按钮,在ProcessorController Angular文件中调用“LoadProcessors()”函数。 “LoadProcessors()”函数将在主控制器中重复使用相同的网格定义,但列defs和网格数组将不同。

<input style="margin-top: 8px !important; margin-bottom: 8px !important; margin-left: 8px !important;" type="submit" value="Get Records" ng-controller="PolicyController" ng-click="loadPoliciesGrid()" class="btn btn-default btn-sm">

“PolicyController”中用于加载网格数据的功能如下所示。将有其他Angular控制器调用自己的数据,主控制器中的网格定义应该以某种方式具有相应的列defs:

//PolicyController in policy.js
(function () {

angular.module('CRNApp');

PolicyController.$inject = ['$scope', '$http', '$uibModal', '$log'];

angular.module('CRNApp')
    .controller('PolicyController', PolicyController);

function PolicyController($scope, $http, $uibModal, $log) {

    $scope.loadPoliciesGrid = function () {
        $scope.$parent.loading = true;
        $http.get("/api/Policy")
            .then(function (responsePol) {
                $scope.$parent.policyData = responsePol.data;
                $scope.$parent.showGrid = 'policies';
                $scope.$parent.loading = false;
            })
            .catch(function (error) {
                console.log(error);
            });
    };

};
}());

网格模板绑定到Index.cshtml页面中的策略控制器,该页面将作为子页面加载到主_Layout.cshtml页面中。这些模板中的每一个都应该将它们的数据绑定到同一个UI网格。:

@*Index.cshtml. Each template is bound to a different Angular controller*@
@{ViewBag.Title = "ICS Portal - Home Page";}
<div ng-include="'templates/policiesGrid.cshtml'" ng-controller="PolicyController"></div>
<div ng-include="'templates/processorGrid.cshtml'" ng-controller="ProcessorController"></div>
<div ng-include="'templates/usersGrid.cshtml'" ng-controller="UserController"></div>

网格标记容器在一个名为policiesgrid.cshtml的单独模板文件中定义。每个网格标记模板都在一个单独的文件中,但是shoudl引用相同的UI网格定义:

<div style="margin-left: auto; margin-right: auto;">
    <div ui-if="policyList.data.length>0" ng-style="getPolicyTableHeight()"
     ui-grid-auto-resize ui-grid-empty-base-layer ui-grid-selection id="policyGrid"
     ui-grid="policyList" class="processorGrid" ng-show="showGrid == 'policies'"
     style="margin-left: auto; margin-right: auto;">
    </div>
</div>

1 个答案:

答案 0 :(得分:1)

您应该使用服务来获取数据,但无论如何,有很多方法可以实现您想要的(如AngularJS中的所有内容)。如果您不想重构代码,并且我理解正确,您希望控制器之间进行基本通信。

最简单的方法是使用网格在控制器上设置观察器。

因此,在设置网格的控制器上执行以下操作:

$scope.$on('dataGridChangedMessage', (event, argumentsPassedToGrid) => {
    $scope.policyList.columnDefs = argumentsPassedToGrid.columnDefs;
    $scope.policyList.data = argumentsPassedToGrid.data;
    // you might neeed here to refresh the grid using API, something like: policyApi.grid.refresh();
    // or try to trigger digest cycle manually if it doesn't work with: $timeout($scope.$apply()); 
});

在你的其他控制器上,你需要注入$ rootScope并广播你的数据/ columnDefs - 当你的$ http承诺得到解决时:

$rootScope.$broadcast('dataGridChangedMessage', {
    columnDefs: [],  // this is your new column defs
    data: [] // this is your new data
};

所以你可以让ui网格控制器显示数据和控制器发送类似的数据:

controller1 =&gt;控制器UI GRID&lt; = controller2

即使上面会有效,但更好的方法是:

  • 创建全新的服务,

  • 在控制器UI GRID中注入服务,

  • 删除那些控制器(在我的示例中为controller1和controller2)

  • 从服务中返回$ http承诺 - 甚至更好地设置$resource并将其用于不同的终端。

  • 从服务中获取不同的数据(在UI GRID控制器中)并且一旦承诺 解决了你只需刷新网格数据(类似于上面的例子)

  • 所以只使用一个控制器和一个服务 - 没有必要进行$ broadcasts

如果您担心重复,可以设置显示网格数据的通用组件,在服务和通用功能上设置$ resource - 这将需要您可以在模板中设置的两个或任意数量的参数。如果你正在使用组件(你应该)/指令:

,就像这样
<my-ui-grid-generic-component url-key="some-name-1" url-params="{something: whatever}"></my-ui-grid-generic-component>

并且在服务中你会用键定义对象 - 像这样的端点:

let uigridDataAPIs = {
  'some-name-1': 'http://google.com',
  'some-name-2': 'http://google.com',
};

一旦在主控制器中注入该服务,您只需要一个通用组件/指令控制器上的函数来调用service $ resource - 如下所示:

MyInjectedService.getResource($scope.urlKey, $scope.urlParams).then(resolve => { // logic to update grid - similar to first example });

您需要设置泛型$ http函数或$ resource,以返回该服务的promise。别忘了在组件/指令上设置urlKey和urlParams绑定。

此外,如果您想学习更高级的做事方式,请查看:

我强烈推荐这一个:https://github.com/toddmotto/angularjs-styleguide

https://github.com/angular-redux/ng-redux

https://rxjs-dev.firebaseapp.com/

请记住以上所有内容只是为了指明未来的正确方向,我还没有对我写过的任何东西进行过测试 - 大多数都是假设的,并且我已经将它设置在带有ui-grid&#的项目上39; s,所以你需要填补空白,一旦你进入下一步并陷入困境 - 发一个新问题,有人会帮助你。