AngularJS:创建映射到REST资源的对象(ORM风格)

64

我对AngularJS还比较陌生,不太清楚如何将其与我的服务器REST API后端结合起来。

例如,假设我有一个“image”资源,可以通过GET访问:myApi/image/1/。这会返回一个包含各种字段的JSON对象。比如说:

{url: "some/url", date_created: 1235845}

现在,我希望在我的AngularJS应用程序中有一个关于这个"Image"对象的某种表现形式。这个表现形式不仅仅是字段的映射 - 我想添加“助手”函数,例如将date_create字段转换为可读的日期格式。

我知道$resource服务,但我不清楚如何创建一个基本的Angular类,该类使用Resource获取JSON对象,然后通过添加各种辅助函数来增强它。

加分项:

我也不清楚如何在模型之间添加“关系”。例如,我可能有一个嵌套了“image”资源的“user”资源,并且我希望获取User资源,但能够在模型的“Image”部分上调用“Image”助手函数。


这听起来像是你想要一种由Angular支持的模型框架。据我所知,Angular内置并没有类似的东西。 - thalador
3
@thalador - 我想了解建立自己的方法最佳实践,甚至仅仅是听一下。我应该用一个服务来包装“资源”对象并添加方法吗?或者使用单独的服务来包装“资源”对象呢?等等。 - Edan Maor
7个回答

80

JSData
JSData 项目最初是一个名为 angular-data 的项目,现在已经成为“一个构建于易用性和安心之上的跨框架数据存储库”。 它具有出色的文档,并支持关系、多后端(http、localStorage、firebase)、验证以及 Angular 集成。
http://www.js-data.io/

BreezeJS
AngularJS YouTube 频道 中有 视频使用了 BreezeJS

BreezeJS 是一个高级的 ORM,甚至支持客户端过滤和其他很酷的功能。 它最适合支持 OData 的后端,但也可以在其他类型的后端上工作。

ngResource
另一种选择是使用ngResource,以下是如何扩展它并添加自己的函数的示例:

module.factory('Task', function ($resource) {
    var Task = $resource(WEBROOT + 'api/tasks/:id', {id: '@id'}, {update: { method: 'PUT'}});
    angular.extend(Task.prototype, {

        anExampleMethod: function () {
            return 4;
        },

        /**
         * Backbone-style save() that inserts or updated the record based on the presence of an id.
         */
        save: function (values) {
            if (values) {
                angular.extend(this, values);
            }
            if (this.id) {
                return this.$update();
            }
            return this.$save();
        }
    });
    return Task;
});

我发现相比于Backbone.Model,ngResource非常有限,后者具有以下特点:
  • 可以通过Model.parse进行自定义JSON解析
  • 可以扩展BaseModel(而ngResource中没有baseUrl)
  • 其他钩子,如Backbone.sync,可以启用LocalStorage等功能。
Restangular
“用于正确且轻松地处理Rest API Restful资源的AngularJS服务”
https://github.com/mgonto/restangular 或尝试其他ORM
https://stackoverflow.com/questions/6786307/which-javascript-orm-to-use

1
Breeze可能是您的正确选择(免责声明:我是Breeze维护者之一)。明确地说,Breeze是一个纯JavaScript库。它不是ORM。它不关心OData。它可以与ORM、OData和其他.NET技术很好地配合使用,这也是我们通常演示它的方式。但是,您可以访问几乎任何使用任何技术编写的HTTP服务(包括REST服务),正如Breeze Edmunds示例所演示的那样。如果您有Breeze问题,请在SO上提问,并标记为“breeze”,我们会找到它。 - Ward
我认为Breeze是正确的长期选择,也是我们下一个项目一定会考虑的。对于这个项目,我们将继续使用ngResource和自定义函数。 - Edan Maor
最后一个链接已经失效。 - Stefan
@Stefan 谢谢,我已经更新了链接。请注意这些链接是针对 AngularJS 1.x 版本的。 - Bob Fanger

15

我是 Restangular 的创建者,所以我的观点可能会有偏见。

但正如 Bob 所说,您可以使用 Restangular 来完成这个任务。

Restangular 使用您的 Restful API 资源来遍历树形结构。您还可以添加新方法。

以下是一个编码示例:https://github.com/mgonto/restangular#lets-code

通过这种方式,您可以向对象添加新方法(加分项 :)):https://github.com/mgonto/restangular#creating-new-restangular-methods

希望这对您有用 :)

否则,您也可以使用 ngResource ($ resource) 完成此操作,但在我看来,它需要一些 "爱" 和 "糖果"。

最好的祝福


7

5
经过大量研究,这里列出了所有可用解决方案的全面清单: 但是,老实说我并不是很满意,所以我决定在列表中添加自己的解决方案哈哈。请查看这里:$modelFactory
最终的代码结果大致如下:
var module = angular.module('services.zoo', ['modelFactory']);

module.factory('AnimalModel', function($modelFactory){
  return $modelFactory('api/zoo');
});

return module;

我相信这是比其他解决方案更好的,因为它的模型定义与Angular的ngResource非常相似,仅添加了缺少的基础功能。它非常轻(1.45k gzip/min),只有一些小依赖项(没有lodash、jquery等)。


4

ModelCore(https://github.com/klederson/ModelCore )的工作方式与此相似,而且非常容易实现:

var ExampleApp = angular.module('ExampleApp', ['ModelCore']); //injecting ModelCore

ExampleApp.factory("Users",function(ModelCore) {
  return ModelCore.instance({
    $type : "Users", //Define the Object type
    $pkField : "idUser", //Define the Object primary key
    $settings : {
      urls : {
        base : "http://myapi.com/users/:idUser",
      }
    },
    $myCustomMethod : function(info) { //yes you can create and apply your own custom methods
        console.log(info);
    }
  });
});

//Controller
function MainCrtl($scope, Users) {
  //Setup a model to example a $find() call
  $scope.AllUsers = new Users();

  //Get All Users from the API
  $scope.AllUsers.$find();

  //Setup a model to example a $get(id) call
  $scope.OneUser = new Users();

  //Hey look there are promisses =)
  //Get the user with idUser 1 - look at $pkField
  $scope.OneUser.$get(1).success(function() {
    console.log("Done!",$scope.OneUser.$fetch());
});

3

Angular Rest-Mod 是基于 Angular 的另一个很好的模型 / ORM 选项。

Restmod 创建对象,您可以从 Angular 中使用这些对象与 RESTful API 进行交互。它还支持集合、关联、生命周期钩子、属性重命名等功能。


你能否加上一些例子吗? - blackjid

2

这是关于ngResource的助手的另一个示例。它依赖于这样的事实,即绝大多数服务都是类似于以下内容:

http://host/api/posts
http://host/api/posts/123
http://host/api/posts/123/comments
http://host/api/posts/123/comments/456

因此,任务是创建一个辅助工具,它可以创建 AngularJS 资源对象,并映射到这些服务。下面是代码:

'use strict';

var api = angular.module('api', ['ngResource']);

// RESTful API helper
api.addService = function (serviceNameComponents) {
    var serviceName = "";
    var resource = "/api"; // Root for REST services
    var params = {};

    serviceNameComponents.forEach(function (serviceNameComponent) {
        serviceName += serviceNameComponent;

        var lowerCaseServiceNameComponent = serviceNameComponent.toLowerCase();
        var collection = lowerCaseServiceNameComponent + 's';
        var id = lowerCaseServiceNameComponent + 'Id';

        resource += "/" + collection + "/:" + id;
        params[id] = '@' + id;
    });

    this.factory(serviceName, ['$resource',
        function ($resource) {
            return $resource(resource, {}, {
                    query: {
                        method: 'GET',
                        params: params,
                        isArray: true
                    },
                    save: {
                        method: 'POST',
                    },
                    update: {
                        method: 'PUT',
                        params: params,
                    },
                    remove: {
                        method: 'DELETE',
                        params: params,
                    }
                }
            );
        }
    ]);
}

所以,要使用它只需调用这个帮助程序

api.addService(["Post"]);
api.addService(["Post", "Comment"]);

然后您可以在代码中使用Post和PostComment,并像这样使用所需的参数:post_id。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接