在AngularJS中组合CREATE和EDIT控制器是一种好习惯吗?

时间:2014-07-30 20:21:14

标签: angularjs controller crud

CREATE和EDIT控制器中有许多重复的代码。 这些控制器可以合并为一个,以最大限度地减少重复代码。

问题:我需要区分在表单提交时使用哪种方法 - 例如create()或edit()。

解决方案:我可以添加$scope.mode例如,如果用户点击“编辑”按钮则设置$scope.mode='edit',或者如果用户点击“添加”则设置$scope.mode='add'按钮。

我可以使用服务来减少重复代码,但仍然会有重复的代码。例如,在两个控制器中,我有cancel()方法,它清除表单并隐藏它。我可以在服务中存储clearForm()和hideForm(),但这些代码将在两个控制器中重复:

$scope.cancel = function() {
    Service.clearForm();
    Service.hideForm();
};

问题:

  • 在AngularJS中合并CREATE和EDIT控制器是不错的做法?
  • 是否有任何良好做法可以最大限度地减少重复代码?

3 个答案:

答案 0 :(得分:31)

是。使用1个控制器。

以下是使用1控制器的原因

控制器的工作是支持View。您的创建视图和编辑视图完全相同 - 只有一个数据预先填充(编辑)而另一个没有(创建)。 此外,"目的"此视图是让用户更改或在表单中输入新值。你唯一的区别应该是重置()。但即使在那里你也可以从一个空模型对象开始,例如如果是CREATE,则为$scope.entity = {},您将从$scope.entity = $http.get()开始。

2个控制器的重复问题

使用2种不同的控制器和服务,您将至少产生以下重复:

$scope.cancel = function() {
    Service.cancel();
};

$scope.validate = function() {
   ValidtionSvc.validate();
}
.
.
.//other stuff similar

但问题是为什么即使像你所说的那样重复。

(由于上面是第一个问题的答案,因此在此处进行了修改)

如何重复使用1个控制器?

  

是否有任何良好做法可以最大限度地减少重复代码?

问题重新定义:在CREATE和EDIT表单中是否有消除重复代码的良好做法?

没有正式的最佳做法'据我所知,在这种特定情况下避免重复代码。但是我建议不要使用mode = edit / create。在这种情况下控制器的原因应该几乎没有区别,因为他们的工作是纯粹在用户交互时获取/更新模型。

以下是您在这种情况下遇到的区别以及如何使用mode = create / edit来避免if / then / else:

1)使用现有值和创建的空表单填充表单。

要获取现有实体,您需要一些键/查询数据。如果存在此类关键数据,您可以

var masterEntity = {};
if(keyData) {
   masterEntity = MyEntityResourceFactory.getEntity(keyData);
} 
$scope.entity = masterEntity;//for Create this would be {}

2)reset()表单    应该只是

   $scope.reset = function() {
      $scope.entity = masterEntity;
   }

3)更新/创建

$http.post()//should not be different in today's world since we are treating PUT as POST

4)验证 - 这是一个完美的重用 - 应该没有差异。

5)初始/默认值

您可以使用masterEntity = Defaults而不是{}。

答案 1 :(得分:11)

  

将CREATE和EDIT控制器组合在一起是不错的做法   AngularJS?

根据我的经验,这是99.9%的时间是个好主意。我通常通过$ routeProvider解析功能将 formType 变量注入我的控制器。所以我会有以下内容:

$routeProvider
    .when('/item/create', {
        templateUrl: '/app/item/itemForm.html',
        controller: 'itemFormController',
        resolve: {
            item: ['$route', 'itemRepository', function ($route, itemRepository) {
                return itemRepository.getNew();
            }],
            formType: function () { return Enums.FormType.CREATE; }
        },
    })
    .when('/item/edit/:itemId', {
        templateUrl: '/app/item/itemForm.html',
        controller: 'itemFormController',
        resolve: {
            item: ['$route', 'itemRepository', function ($route, itemRepository) {
                return itemRepository.get($route.current.params.itemId);
            }],
            formType: function () { return Enums.FormType.EDIT; },
        },
    });

这样你就可以将你的实体和表单动作类型注入控制器。我也共享相同的模板,因此保存表单我可以依赖我的存储库/服务来确定要调用的REST端点,或者我可以在控制器内部进行简单的检查,具体取决于注入的formType。

  

是否有任何良好做法可以最大限度地减少重复代码?

我用来保持干燥的一些事情:

如果您在服务器API上保持一个通用约定,那么您可以使用基本工厂/存储库/类(无论您想要调用它)进行数据访问。例如:

GET  -> /{resource}?listQueryString     // Return resource list
GET  -> /{resource}/{id}                // Return single resource
GET  -> /{resource}/{id}/{resource}view // Return display representation of resource
PUT  -> /{resource}/{id}                // Update existing resource
POST -> /{resource}/                    // Create new resource
etc.

然后我们使用一个返回基础存储库类的AngularJs工厂,让我们调用它abstractRepository。然后,对于每个资源,我为原型继承自abstractRepository的特定资源创建一个具体的存储库,因此我从abstractRepository继承了所有共享/基本功能,并为具体存储库定义了任何特定于资源的功能。这样,绝大多数数据访问代码都可以在abstractRepository中定义。以下是使用Restangular的示例:

<强> abstractRepository

app.factory('abstractRepository', [function () {

    function abstractRepository(restangular, route) {
        this.restangular = restangular;
        this.route = route;
    }

    abstractRepository.prototype = {
        getList: function (params) {
            return this.restangular.all(this.route).getList(params);
        },
        get: function (id) {
            return this.restangular.one(this.route, id).get();
        },
        getView: function (id) {
            return this.restangular.one(this.route, id).one(this.route + 'view').get();
        },
        update: function (updatedResource) {
            return updatedResource.put();
        },
        create: function (newResource) {
            return this.restangular.all(this.route).post(newResource);
        }
        // etc.
    };

    abstractRepository.extend = function (repository) {
        repository.prototype = Object.create(abstractRepository.prototype);
        repository.prototype.constructor = repository;
    };

    return abstractRepository;
}]);

具体的存储库,我们以客户为例:

app.factory('customerRepository', ['Restangular', 'abstractRepository', function (restangular, abstractRepository) {

    function customerRepository() {
        abstractRepository.call(this, restangular, 'customers');
    }

    abstractRepository.extend(customerRepository);
    return new customerRepository();
}]);

如果使用此基本存储库模式,您会发现大多数CRUD控制器也会共享许多公共代码,因此我通常会创建一个控制器继承的基本CRUD控制器。有些人不喜欢基本控制器的想法,但在我们的例子中它也有用。

答案 2 :(得分:1)

第一个问题的答案可能取决于具体情况。

如果两个控制器共享大量操作,并且只需要改变一个或两个函数的行为 - 为什么不呢!也许不是最优雅的解决方案,但嘿,无论有用。

如果许多或所有控制器操作的行为都依赖于'$ scope.mode'......我会说要小心。这似乎是一条危险的道路。

在最大限度地减少控制器之间的代码复制方面,Angular服务一直很有用。如果有一个“减少重复代码的良好做法”,我会说这将是服务。它们是您应用程序的全局应用程序,可以毫无问题地注入多个控制器。

我希望有所帮助!