CREATE和EDIT控制器中有许多重复的代码。 这些控制器可以合并为一个,以最大限度地减少重复代码。
问题:我需要区分在表单提交时使用哪种方法 - 例如create()或edit()。
解决方案:我可以添加$scope.mode
例如,如果用户点击“编辑”按钮则设置$scope.mode='edit'
,或者如果用户点击“添加”则设置$scope.mode='add'
按钮。
我可以使用服务来减少重复代码,但仍然会有重复的代码。例如,在两个控制器中,我有cancel()方法,它清除表单并隐藏它。我可以在服务中存储clearForm()和hideForm(),但这些代码将在两个控制器中重复:
$scope.cancel = function() {
Service.clearForm();
Service.hideForm();
};
问题:
答案 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服务一直很有用。如果有一个“减少重复代码的良好做法”,我会说这将是服务。它们是您应用程序的全局应用程序,可以毫无问题地注入多个控制器。
我希望有所帮助!