应用程序设计问题。我有一个项目,它有很多高度自定义的输入。每个输入都是作为一个指令实现的(Angular使得开发成为一种绝对的快乐)。
输入会在模糊时保存数据,因此无法提交表单。这一直很有效。
每个输入都有一个名为“saveable”的属性,它驱动另一个由所有这些输入类型共享的指令。 Saveable指令使用$ resource将数据发布回API。
我的问题是,这个逻辑应该在一个指令中吗?我最初把它放在那里是因为我认为我需要多个控制器中的保存逻辑,但事实证明它们确实发生在同一个控制器中。另外,我读到了某个地方(丢失了引用),该指令是放置API逻辑的不好的地方。
此外,我需要尽快为这种保存逻辑引入单元测试,测试控制器似乎比测试指令更简单。
提前致谢; Angular的文档可能是......如果......但是社区中的人们都是巨型的。
[编辑]一个非功能性的,简化的看看我正在做的事情:
<input ng-model="question.value" some-input-type-directive saveable ng-blur="saveModel(question)">
.directive('saveable', ['savingService', function(savingService) {
return {
restrict: 'A',
link: function(scope) {
scope.saveModel = function(question) {
savingService.somethingOrOther.save(
{id: question.id, answer: question.value},
function(response, getResponseHeaders) {
// a bunch of post-processing
}
);
}
}
}
}])
答案 0 :(得分:2)
不,我认为该指令不应该调用$http
。我会创建一个服务(使用Angular中的factory
)或(最好)模型。当它在模型中时,我更喜欢使用$resource
服务来定义我的模型“类”。然后,我将$http
/ REST代码抽象为一个漂亮的活动模型。
答案 1 :(得分:2)
这方面的典型答案是您应该为此目的使用服务。以下是有关此问题的一般信息:http://docs.angularjs.org/guide/dev_guide.services.understanding_services
这是plunk with code modeled after your own starting example:
示例代码:
var app = angular.module('savingServiceDemo', []);
app.service('savingService', function() {
return {
somethingOrOther: {
save: function(obj, callback) {
console.log('Saved:');
console.dir(obj);
callback(obj, {});
}
}
};
});
app.directive('saveable', ['savingService', function(savingService) {
return {
restrict: 'A',
link: function(scope) {
scope.saveModel = function(question) {
savingService.somethingOrOther.save(
{
id: question.id,
answer: question.value
},
function(response, getResponseHeaders) {
// a bunch of post-processing
}
);
}
}
};
}]);
app.controller('questionController', ['$scope', function($scope) {
$scope.question = {
question: 'What kind of AngularJS object should you create to contain data access or network communication logic?',
id: 1,
value: ''
};
}]);
相关的HTML标记:
<body ng-controller="questionController">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="saveModel(question)" />
</body>
仅使用factory
和现有ngResource服务的替代方案:
但是,您也可以使用factory
和ngResource,以便重复使用某些常见的“保存逻辑”,同时仍然可以为不同类型的对象/数据提供变体。你想保存或查询。而且,这种方式仍然只会导致您的特定对象类型的保护程序的单个实例化。
使用MongoLab集合的示例
我做过类似的事情,以便更容易使用MongoLab集合。
这个想法的要点是这个片段:
var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections";
var apiKey = "YOUR API KEY";
var collections = [
"user",
"question",
"like"
];
for(var i = 0; i < collections.length; i++) {
var collectionName = collections[i];
app.factory(collectionName, ['$resource', function($resource) {
var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey);
var svc = new resourceConstructor();
// modify behavior if you want to override defaults
return svc;
}]);
}
备注:强>
dbUrl
和apiKey
当然是特定于您自己的MongoLab信息createResource
函数(您可以在plunk和下面的代码中看到),它实际上处理了使用ngResource原型创建构造函数。svc
实例以按集合类型consoleLog
函数,并将一些调试信息写入控制台以供说明。createResource
函数本身被调用的次数,作为一种证明,即使实际上有两个控制器,questionController
和questionController2
要求同样的注射,工厂总共被召唤3次。完整代码:
HTML:
<body>
<div ng-controller="questionController">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="save(question)" />
</div>
<div ng-controller="questionController2">
<h3>Question<h3>
<h4>{{question.question}}</h4>
Your answer: <input ng-model="question.value" saveable ng-blur="save(question)" />
</div>
</body>
JavaScript的:
(function() {
var app = angular.module('savingServiceDemo', ['ngResource']);
var numberOfTimesCreateResourceGetsInvokedShouldStopAt3 = 0;
function createResource(resourceService, resourcePath, resourceName, apiKey) {
numberOfTimesCreateResourceGetsInvokedShouldStopAt3++;
var resource = resourceService(resourcePath + '/' + resourceName + '/:id',
{
apiKey: apiKey
},
{
update:
{
method: 'PUT'
}
}
);
resource.prototype.consoleLog = function (val, cb) {
console.log("The numberOfTimesCreateResourceGetsInvokedShouldStopAt3 counter is at: " + numberOfTimesCreateResourceGetsInvokedShouldStopAt3);
console.log('Logging:');
console.log(val);
console.log('this =');
console.log(this);
if (cb) {
cb();
}
};
resource.prototype.update = function (cb) {
return resource.update({
id: this._id.$oid
},
angular.extend({}, this, {
_id: undefined
}), cb);
};
resource.prototype.updateSafe = function (patch, cb) {
resource.get({id:this._id.$oid}, function(obj) {
for(var prop in patch) {
obj[prop] = patch[prop];
}
obj.update(cb);
});
};
resource.prototype.destroy = function (cb) {
return resource.remove({
id: this._id.$oid
}, cb);
};
return resource;
}
var dbUrl = "https://api.mongolab.com/api/1/databases/YOURDB/collections";
var apiKey = "YOUR API KEY";
var collections = [
"user",
"question",
"like"
];
for(var i = 0; i < collections.length; i++) {
var collectionName = collections[i];
app.factory(collectionName, ['$resource', function($resource) {
var resourceConstructor = createResource($resource, dbUrl, collectionName, apiKey);
var svc = new resourceConstructor();
// modify behavior if you want to override defaults
return svc;
}]);
}
app.controller('questionController', ['$scope', 'user', 'question', 'like',
function($scope, user, question, like) {
$scope.question = {
question: 'What kind of AngularJS object should you create to contain data access or network communication logic?',
id: 1,
value: ''
};
$scope.save = function(obj) {
question.consoleLog(obj, function() {
console.log('And, I got called back');
});
};
}]);
app.controller('questionController2', ['$scope', 'user', 'question', 'like',
function($scope, user, question, like) {
$scope.question = {
question: 'What is the coolest JS framework of them all?',
id: 1,
value: ''
};
$scope.save = function(obj) {
question.consoleLog(obj, function() {
console.log('You better have said AngularJS');
});
};
}]);
})();
答案 2 :(得分:0)
通常,与UI相关的事物属于指令,与输入和输出(来自用户或服务器)的绑定相关的事物属于控制器,与业务/应用程序逻辑相关的事物属于在服务(某种程度上)。我发现这种分离导致我的代码非常干净。