1

我有一个应用程序使用多个选项卡,每个选项卡中都有一个网格。我有多个页面使用相同的配置。

我有一个适用于所有网格的控制器。我想在整个应用程序中重用这个控制器。

我的问题是我试图延迟加载每个选项卡的数据,直到单击该选项卡。我想不通的是如何告诉控制器哪个范围属于哪个选项卡,并且只获取该网格的数据。我在内部知道 AngularJs 会这样做,因为如果我一次加载每个选项卡的所有数据,我可以单击每个选项卡的分页器、搜索等,并且只更新该范围。

我为每个选项卡设置了 ng-click 设置,并且可以在单击选项卡时触发我的控制器。但是,控制器调用所有实例化的范围来为它们各自的网格加载数据。

我的方法可能不是最好的,但创建执行完全相同操作的单独控制器似乎很愚蠢。

注意:带有引导程序的 Angular UI 选项卡不是一个选项。

我的观点

<div ng-app="TabsApp">
    <div tabs>
        <div class="tabs">
            <a ng-click="clickTab(0)" ng-class="{selected: selectedTab==0}">Localized Text From Server</a>
            <a ng-click="clickTab(1)" ng-class="{selected: selectedTab==1}">Localized Text From Server</a>
            <a ng-click="clickTab(2)" ng-class="{selected: selectedTab==2}">Localized Text From Server</a>
        </div>
        <div class="tab-content">
            <div ng-show="selectedTab==0" ng-init="init(@Model.UserId, 'useraddresses')" ng-controller="ListCtrl">@Html.Partial("_Grid0")</div>
            <div ng-show="selectedTab==1" ng-init="init(@Model.UserId, 'userphones')" ng-controller="ListCtrl">@Html.Partial("_Grid1")</div>
            <div ng-show="selectedTab==2" ng-init="init(@Model.UserId, 'usernotes')" ng-controller="ListCtrl">@Html.Partial("_Grid2")</div>
        </div>
    </div>
</div>

我的应用和工厂网址

var TabsApp = angular.module("TabsApp", ['ngResource', 'ngRoute']);

TabsApp.factory('Api', function($resource){
    return $resource('/api/user/:userId/:ctrl', { userId: '@userId', ctrl: '@ctrl'});
});

我的控制器 - 子范围

var ListCtrl = function ($scope, $location, Api){
    $scope.search = function () {
        Api.get({
            userId: $scope.userId,
            ctrl: $scope.ctrl,
            q: $scope.query
            //etc.
            },
                function(data){
                    $scope.items = data.items;
                    //other mapping
                });
    };

    $scope.init = function(userId, ctrl){
        $scope.userId = userId;
        $scope.ctrl = ctrl;
    };
    $scope.reset = function(){
        $scope.items = [];
        $scope.search();
    };

    //kind of a hack but broadcasting was the only way I could figure out to listen for tab changes
    $scope.tabModelChange = { 'isChanged': false };
    $scope.$on('tabModelChange', function(event, args) {
        $scope.tabModelChange.isChanged = true;
        var activeTab = args.val[$scope.selectedTab];
        if (!activeTab.isLoaded) {
            $scope.reset();
        }
    }); 

    //filtering, sorting, pagination, etc.
};

我的指令:父范围

TabsApp.directive('tabs', function () {
    return {
        controller: function ($scope, $element) {
            $scope.selectedTab = 0;
            $scope.tabModel = [];

            //I use localized text and any number of tabs on my views from the server so the client wont know how many tabs each view will have
            var tabs = angular.element($element.children()[1]).children();
            angular.forEach(tabs, function (value, key) {
                $scope.tabModel.push({'isLoaded' : false, 'isActive': false});
            });
            $scope.clickTab = function(tab) {
                $scope.selectedTab = tab;
                $scope.tabModel[$scope.selectedTab].isActive = true;
            };
            $scope.$watch('tabModel', function(newVal, oldVal) {
                if (newVal !== oldVal) {
                    $scope.$broadcast('tabModelChange', { 'val': newVal });
                }
            }, true);
        }
    };
});

我怀疑当我的控制器收到选项卡模型已更改的广播时,它会调用 $scope.reset ,其中 $scope 是父范围,然后遍历子范围寻找“重置”。因为有 3 个 ListCtrl 实例,所以父作用域会找到 3 个带有“reset”的子作用域。因此,所有数据都会立即加载。

如何获得 $scope.reset 以匹配单击的选项卡?谢谢。

4

2 回答 2

2

我认为,只需对现有代码进行最少的更改,这是一个可以满足您需求的 plunker。

http://plnkr.co/edit/TVwWQehgWJay7ngA8g6B?p=preview

基本上,我创建了第二个指令tab,该指令接受一个参数,该参数是一个用于评估何时切换到该选项卡的函数。

TabsApp.directive('tab', function () {
    return {
        require: '^tabs',
        link: function (scope, element, attrs, tabsCtrl) {
            tabsCtrl.add({
                'isLoaded' : false, 
                'isActive': false, 
                'changed': function () { scope.$eval(attrs.tab); }
            });
        }
    };
});
于 2013-10-31T20:53:20.263 回答
1

这是我们所做的(我有点懒,打算使用我们的代码),我们在单击选项卡时加载。

这是标签

    <ul class='nav nav-pills'>        
        <li ng-class="{ active : mode == 'incomplete'}"><a tabindex="-1" href="#/incomplete" ng-click='mode="incomplete"'>Incomplete orders</span></a></li>        
        <li ng-class="{ active : mode == 'completed'}"><a tabindex="-1" href="#/completed" ng-click='mode="completed"'>Completed orders</a></li>
    </ul>

我们设置路线

.config(['$routeProvider', '$env', function ($routeProvider, $env) {
     $routeProvider.when("/completed", {
        templateUrl: $env.urlRoot + "content/partials/orders/completed.htm",            controller: 'CompletedOrdersCtrl'
     });
    $routeProvider.when("/incomplete", {
        templateUrl: $env.urlRoot + "content/partials/orders/incomplete.htm",  controller: 'IncompleteOrdersCtrl'
     });
     $routeProvider.otherwise({
        templateUrl: $env.urlRoot + "content/partials/orders/incomplete.htm", controller: 'IncompleteOrdersCtrl'
     });
} ]);

然后我们有两个控制器 IncompleteOrdersCtrl 和 CompleteOrdersCtrl 调用服务来获取正确的数据。您可以通过在路由配置中传递的参数将其整合到一个控制器中。

希望这对你有用

- 担

于 2013-10-31T20:30:50.820 回答