原文地址:www.sitepoint.com/creating-cr…
大量的单页应用都有CRUD操作。如果你使用angularjs创建一个CRUD操作,那么你可以利用$resource服务的优势。建立在$http服务之上,angularjs的$resource是一个 factory ,这样使前后端使用RESTful标准进行交互变得简单。所以,我们一起探索一下$resource,并且在angular中实现CRUD的操作。
前提
$resource服务没有打包到angularjs中。你需要下载一个独立的文件叫angular-resource.js并且把它引入到HTML页面中。这个文件可以从这里下载:cdnjs.cloudflare.com/ajax/libs/a…。
另外,为了使用$resource你需要在主模块中注入ngResource模块。示例:
angular.module('mainApp',['ngResource']); //mainApp is our main module
入门
$resource和 RESTful API工作。这意味着你的 URLs 应该类似于下面的模式:
你可以创建接口使用你选择的服务器端语言。我使用的是Node + Express + MongoDB为这个示例应用设计RESTful接口。创建好了这些URLs以后,你就可以借助于$resource与这些URLs交互。我们来看一下$resource实际上是怎么工作的。
$resource是怎么工作的?
在controller/service中使用$resource需要先声明依赖。接下来就像下面的示例一样,在REST端调用$resource()方法。调用方法之后返回一个$resource一个可用于与REST后端交互的资源类:
angular.module('myApp.services').factory('Entry', function($resource) {
return $resource('/api/entries/:id'); // Note the full endpoint address
});
方法返回的是一个资源类对象,默认包含下面5种方法:
get()query()save()remove()delete()
下面我们看一下如何在controller中使用get(),query()和save()方法:
angular.module('myApp.controllers',[]);
angular.module('myApp.controllers').controller('ResourceController',function($scope, Entry) {
var entry = Entry.get({ id: $scope.id }, function() {
console.log(entry);
}); // get() 返回单个entry
var entries = Entry.query(function() {
console.log(entries);
}); //query() 返回有的entry
$scope.entry = new Entry(); //实例化一个资源类
$scope.entry.data = 'some data';
Entry.save($scope.entry, function() {
//data saved. do something here.
}); //saves an entry. Assuming $scope.entry is the Entry object
});
在上面的代码片段中 get()方法发起/api/entries/:id的 get 请求。参数:id在被替换为$scope.id。注意get()方法返回一个空对象,当实际数据从服务器返回的时候自动填充到这个空对象。get()方法的第二个参数是回调方法,当服务器端返回数据的时候执行该回调。这是一个非常有用的技巧,因为你可以设置get()返回一个空对象,挂载到$scope,绑定视图。当真实的数据返回且填充到对象,双向数据绑定触发,并且更新视图。
query()方法发起/api/entries(注意这里没有:id)的 get请求 并返回一个空数组。当服务器端返回数据时候填充到该数组。将该数组继续挂在到$scope的模型上,并且在视图上使用ng-repeat绑定。你也可以给query()传递一个回调方法,在数据从服务前端返回的时候执行。
save()方法发起/api/entries的 post 请求, 第一个参数是 post body。第二个参数为回调方法,当数据保存成功后执行。你应该记得$resource()方法返回的是一个资源类。所以,在我们的用例中,我们可以调用new Entry()实例化一个真正的对象,设置若干个属性给它,最后将该对象保存到后端。
假设你只使用get()和query()在resource类上(在我们的例子中resource类是Entry)。所有非 get 请求的方法,例如save()和delete()在new Entry()实例中都能用(在这里称为$resource实例)。不同的是这些方法都以$的开头。所以这些有用的方法为:
$save()$delete()$remove
例如,$save()方法像下面一样使用:
$scope.entry = new Entry(); //这个对象有个$save()方法
$scope.entry.$save(function() {
//$scope.entry序列化为json作为post body 发送
});
我们已经实践CRUD中的了增加,查找和删除,剩下的最后一个修改。为了支持修改操作,我们需要像下面这样修改我们的Entryfactory:
angular.module('myApp.services').factory('Entry', function($resource) {
return $resource('/api/entries/:id', { id: '@_id' }, {
update: {
method: 'PUT' // this method issues a PUT request
}
});
});
$resource的第二个 argument 明确标识需要url中:id参数的值是什么。这里将其设置为@_id,这意味着在$resource的实例中不管什么时候调用方法例如$update()和$delete(),:id的都会被设置为实例中_id的属性值。这个是为 PUT 和 DELETE 请求使用的。注意第三个 argument,它允许我们给资源类添加自定义方法。如果该方法是一个非 get 请求,在$resource会有一个以$的同名方法。我们看一下如何使用$update方法。假设我们在controller中使用:
$scope.entry = Movie.get({ id: $scope.id }, function() {
// $scope.entry 是
$scope.entry.data = 'something else';
$scope.entry.$update(function() {
//updated in the backend
});
});
当$update()方法调用的时候,过程如下:
Angularjs 知道
$update()方法会触发 URL 为/api/entries/:id的 PUT 请求。读取
$scope.entry._id值,将此值赋给:id并且生成 URL。发起一个请求体为
$scope.entity的 PUT 请求。
同样,如果你想删除一个entry可以像下面这么做:
$scope.entry = Movie.get({ id: $scope.id }, function() {
// $scope.entry 是服务器端返回来的,是一个 Entry 的实例
$scope.entry.data = 'something else';
$scope.entry.$delete(function() {
//gone forever!
});
});
它和 update 有着同样的步骤,只是使用 DELETE 替换了 PUT请求类型。
我们已经覆盖了CRUD的所有操作,但是还有一小点。$resource方法还有第4个可选择的参数。这是一个自定义设置的值。目前只有一个 stripTrailingSlashes可以设置。它的默认值是false,这意味着它会自动删除 URL 的最后一个 /,如果你不需要可以像下面这么做:
angular.module('myApp.services').factory('Entry', function($resource) {
return $resource('/api/entries/:id', { id: '@_id' }, {
update: {
method: 'PUT' // this method issues a PUT request
}
}, {
stripTrailingSlashes: false
});
});
顺便说一句,我没有覆盖$resource相关的每一个东西。我们这里介绍的是最基本的,这将帮助您很快的开始一个应用的 CRUD。如果你仔细研究$resource,你可以阅读这篇文章。
创建一个Movie的应用
为了加强$resource的概念我们为电影爱好者创建一个应用。这是一个单页应用,用户可以新增一个电影,修改一个已存在的,最后还可以删除。我们将使用$resource与后端 REST API 进行交互。你可以查看这个在线例子,我们将它部署在这里。
注意API允许CROS访问(跨域资源共享),所以你可以创建一个独立的 Angular 应用,可以使用 http://movieapp-sitepointdemo... 地址为API。你可以开发 Angular 应用不用担心没有后端服务。
API
我已经使用 Node 和 Express创建了一个 RESTful 后端服务。看下面的截图认识一下API接口:
目录结构
我们的 AngularJS 应用采用下面的目录结构:
movieApp
/css
bootstrap.css
app.css
/js
app.js
controllers.js
services.js
/lib
angular.min.js
angular-resource.min.js
angular-ui-router.min.js
/partials
_form.html
movie-add.html
movie-edit.html
movie-view.html
movies.html
index.html
注意到我们的路由使用Angular UI Router实现
创建 service 与REST后端交互
像上面部分讨论的一样,我们创建一个标准的 service 使用$resource与后端 REST API 交互。这个服务定义在js/services.js中。
services.js
angular.module('movieApp.services', []).factory('Movie', function($resource) {
return $resource('http://movieapp-sitepointdemos.rhcloud.com/api/movies/:id', { id: '@_id' }, {
update: {
method: 'PUT'
}
});
});
这个 factory 的名字是 Movie. 我们使用的是 MongoDB,每个 movie 实例都有一个_id的属性。rest是简单而直接的。
现在我们已经开发好了 service,我们接下来开发 views 和 controllers。
index.html:创建应用的入口页面
index.html是我们应用的入口。我们需要将所有依赖的 scripts 和 css全部引入到页面。我们使用 Bootstrap 来快速的开始布局。下面是index.html的内容:
The Movie App