我对 AngularJS 比较陌生,我一直在尝试各种方法来使用 Restangular 保持我的 AngularJS CRUD 方法干燥,所以我很感谢社区的任何建议。
我有很多 API 端点,对于每个我想显示一个项目列表,允许选择每个项目(以显示该项目的详细信息)和删除,以及将项目添加到列表中。
到目前为止,我尝试过的每一种方法要么非常不干燥,要么没有正确连接到 $scope,要么有点 hacky...
包装角
将 Restangular 包装到服务中,并使用 addElementTransformer 在返回的集合上设置其他方法似乎是一种不错的方法;和方法很干净,很容易从模板中实现,并在 promise 解决时自动更新列表select
。add
但是,因为该delete
方法实际上是从元素范围(集合的子对象)中调用的,所以在删除后更新列表需要非常可疑地将 $scope 注入服务 - 我能想到的最好的方法如下:
(注意:我通过仅说明单个 API 端点/控制器/模板使示例更易于阅读)
应用程序/js/services.js
function ListTransformer(collection) {
collection.selected = {}
collection.assignedTo = {}
collection.assignedName = ""
collection.add = function(item) {
collection.post(item)
.then(function(response){
collection.push(response);
})
};
collection.delete = function(item, scope) {
item.remove()
.then(function(response){
console.log(item)
console.log(collection)
collection.assignedTo[collection.assignedName] = _.without(collection, item);
})
};
collection.select = function(item) {
this.selected = item;
};
collection.assignTo = function(scope, name) {
scope[name] = collection;
collection.assignedTo = scope
collection.assignedName = name
};
return collection;
};
angular.module('myApp.services', ['restangular'])
.factory('Company', ['Restangular',
function(Restangular){
var restAngular = Restangular.withConfig(function(Configurer) {
Configurer.addElementTransformer('companies', true, ListTransformer);
});
var _companyService = restAngular.all('companies');
return {
getList: function() {
return _companyService.getList();
}
}
}
])
应用程序/js/controllers.js
angular.module('myApp.controllers', [])
.controller('CompanyCtrl', ['$scope', 'Company', function($scope, Company) {
Company.getList()
.then(function(companies) {
companies.assignTo($scope, 'companies'); // This seems nasty
});
}]);
应用程序/partials/companies.html
<ul>
<li ng-repeat="company in companies">
<a href="" ng-click="companies.select(company)">{{company.name}}</a> <a href="" ng-click="clients.delete(client)">DEL</a>
</li>
</ul>
<hr>
{{companies.selected.name}}<br />
{{companies.selected.city}}<br />
扩展基本控制器
我尝试的另一种方法是将模板连接到基本控制器中的服务,我的其他控制器继承了该服务。但是我在这里仍然有 $scope 问题,最终需要从模板中传递范围,这似乎不正确:
(编辑到只是delete
方法)
应用程序/js/services.js
angular.module('myApp.services', ['restangular'])
.factory('ListController', function() {
return {
delete: function(scope, item, list) {
item.remove();
scope.$parent[list] = _.without(scope.$parent[list], item);
}
};
});
应用程序/js/controllers.js
.controller('CompanyCtrl', ['$scope', 'ListController', 'Restangular', function($scope, ListController, Restangular) {
angular.extend($scope, ListController);
$scope.companies = Restangular.all('companies').getList();
}])
应用程序/partials/companies.html
<ul>
<li ng-repeat="company in companies">
<a href="" ng-click="companies.select(company)">{{company.name}}</a> <a href="" ng-click="delete(this, companies, company)">DEL</a>
</li>
</ul>
指令
我对指令有点陌生,但经过大量研究后,似乎它可能是处理这个问题的最AngularJS方法,所以我潜入了。我已经做了很多实验,但请原谅任何明显的错误;基本上问题仍然是,虽然我可以从列表中删除项目,除非我将所有变量传递给指令,否则我无法访问列表最初分配给的 $scope 上的属性,因此它不会在视图中更新。
应用程序/js/directives.js
angular.module('myApp.directives', [])
.directive('delete', function() {
return {
restrict: 'E',
replace: true,
template: '<button>Delete</button>',
link: function (scope, element, attrs) {
element.bind('click', function() {
var item = scope[attrs.item];
item.remove();
scope.$parent[attrs.from] = _.without(scope.$parent[attrs.from], item)
});
},
};
});
应用程序/partials/companies.html
<ul>
<li ng-repeat="company in companies">
<a href="" ng-click="companies.select(company)">{{company.name}}</a> <delete item="company" from="companies">
</li>
</ul>
基本上,我可以让一切正常工作,但似乎我要么必须做很多重复的代码(这是完全错误的),要么将我的范围与我的所有调用一起发送(这似乎也非常错误),或者初始化我的服务通过传递范围(对于我的控制器来说不是最整洁的解决方案,但似乎是实现这一目标的最可维护和最不脆弱的方式。
当然,我可以删除该功能,或将其移至详细视图或复选框/批量操作功能,但我全神贯注于问题并有兴趣找出最佳解决方案 :)
抱歉,如果我遗漏了一些明显的东西!