Angular - 在多个HTTP请求中使用一个控制器来处理许多连贯的视图

时间:2013-12-01 12:44:58

标签: angularjs angularjs-scope

我有一个简单的Angular JS场景。我在一个视图中显示了一个专家列表,该列表包含编辑专家的操作,这将在另一个视图中完成。这些视图来自服务器,不在一个文件中。它们不会一起装载。

<!-- experts.html -->
<div ng-controller='expertController'>
    <!-- showing the list of experts here -->
</div>

在服务器上的另一个文件中我有:

<!-- expert.html -->
<div ng-controller='expertController'>
    <!-- a form to edit/add an expert -->
</div>

我的控制器是:

app.controller('expertController', function ($scope) {
    $scope.getExperts = function () {
        _.get('/expert/getexperts/', null, function (data) {
            $scope.$apply(function () {
                $scope.experts = data;
            });
        });
    };

    $scope.editExpert = function (index) {
        _.get('/expert/getexpert/', { id: $scope.experts[index].Id }, function (data) {
                $scope.$apply(function () {
                    $scope.expert = data;
                });
         });
    };
});

但是,编辑表单中不会显示任何数据。我使用Batarang检查了范围,但expert对象将不会显示。

问题似乎是我为两个(可选两个以上)视图使用一个控制器。但是,正如我在SO上阅读的其他一些问题一样,最佳做法似乎是每个HTML视图都有一个控制器。

但是,我认为让一个expertController执行所有CRUD操作以及与expert相关的其他操作更加一致和一致。我认为编辑表单expertEditController和HTML列表expertListController有点难看。

这里的最佳做法是什么?我怎样才能拥有一个连贯且语义命名的控制器,同时支持许多视图。在我迄今为止看到的任何MVC框架中,通过一个控制器支持许多视图是常规的。

3 个答案:

答案 0 :(得分:17)

当然,您可以使用多个views使用相同的controller。 例如:用于编辑和添加新项目。

但你必须记住,每次加载视图时,控制器都会被初始化,并且会注入新的$scope

在你的情况下,最好只使用两个独立的控制器(一个用于experts,一个用于expert)并使用 - 可选 - 一些服务在这些控制器之间进行通信并可能提供一些缓存机制。

更新如果您想在控制器之间提供一些通用/共享功能,最好的方法是创建,然后inject单独的服务。它保持代码DRY。

答案 1 :(得分:7)

这是一个示例项目(不是由我创建的),它说明了如何使用具有两个视图的单个控制器:一个用于显示项目列表,另一个用于编辑或添加单个项目:http://embed.plnkr.co/jAK31F/

控制器中使用的基本原则是检查是否已传递单个项目的ID并运行适用于该情况的逻辑:

controllers.controller('MainController', function( $scope, $location, $routeParams, ItemService)  {
  if ($routeParams.itemid) {
    // do stuff for single item
    if ($routeParams.itemid == 0) {
      // do stuff for adding item
    } else {
      // do stuff for editing item
    }
  } else {
    // do stuff for listing multiple items
  }
});

不同的视图在路由中配置如下:

app.config(['$routeProvider', function ($routeProvider) {
        // routes
        $routeProvider.
        when('/', {
            templateUrl: 'item_list.html',
            controller: 'MainController'
        }).
        when('/:itemid', {
            templateUrl: 'item_single.html',
            controller: 'MainController'
        });
    }]);

因此,baseurl/这样的网址会打开列表视图,而baseurl/1这样的网址会打开ID为1的项目的详细视图。

关于这是一种最佳实践,在大多数情况下,我不认为这种方法比使用两个控制器更有优势:一个用于列表,一个用于单个项目。根据我的经验,用于查看多个项目的控制器与编辑单个项目的控制器具有不同的关注点。任何共享逻辑都可以按照前面的答案中的建议放在服务中。

答案 2 :(得分:0)

实际上,当我们为其他视图使用相同的控制器时,它会在视图加载时重新加载该控制器。在那一刻,范围将丢失它的数据。为避免这种情况,我使用$ rootScope而不是$ scope。我不知道这种方法是否正确但是有效。

$ rootScope.expert而不是$ scope.expert。