AngularJS - 自定义 $resource

9

我使用 Angular 的 $resource 来进行 REST 服务。由于我的获取响应中存在一些小问题,因此无法将 $resource 服务用于 CRUD 应用程序。

创建一个新对象的操作是可行的(比如说 Card),流程类似于:

var newCard = new CreditCard();
newCard.name = "Mike Smith";
newCard.$save();

Get也能起作用:

var card = CreditCard().get({_id:1)

然而,GET响应并不是Card对象本身,而是包装它的其他消息(包装对象)。

{ message: ".....",
  response: Card //object
}

当我通过资源检索到实例并保存时,它会发送包装对象(响应字段中的修改后的 Card 对象)。 这可能是正确的,但我的服务器期望 Card 对象而不是包装器。 是否有一种方式可以自定义 $resource 以便发送所需对象。根据文档,似乎只能更改 url 参数。
$resource(url[, paramDefaults][, actions]);

你能否在jsfiddle或类似网站上发布一个完整的示例?根据我的经验,对于(简单的)CRUD操作,不必像那样创建一个新对象。如果你只是像这样访问你的资源$scope.card = Card.get({_id:1}),其中Card是你的资源服务,会怎么样呢?此外,如果你告诉你的表单你的模型是什么,实例就会自动填充。 - Narretz
我认为问题不在Angular上。听起来像是服务器端的REST实现存在一些问题。不应该附加任何消息。你可能首先要检查确保响应正文仅包含预期的对象。 - Ben Lesh
服务器确实正在发送实际对象的包装器。但是,是否有一种方法可以仅在发送回服务器(POST)时发送对象? - bsr
1个回答

17

我在$resource模块的标准实现中也遇到了问题。一度我只是在自己本地的$resource文件中进行修改,但我发现他们实现REST资源的方式仍然无法满足我的需求。我需要更多的灵活性。

标准的$resource模块只是对$http的工厂包装器。如果你将$resource模块的代码简化,你可以相当容易地创建自己的自定义实现。

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

app.factory('CreditCard', ['$http', function($http) {

    function CreditCardFactory() {

        function parseMessage(message) {
            if (message.response) {
                return message.response;
            }
        }

        function CreditCard(value) {
            angular.copy(value || {}, this);
        }

        CreditCard.$get = function(id) {
            var value = this instanceof CreditCard ? this : new CreditCard();
            $http({
                method: 'GET',
                url: '/creditcards/' + id
            }).then(function(response) {
                var data = response.data;
                if (data) {
                    angular.copy(parseMessage(data), value);
                }
            });
            return value;
        };

        CreditCard.prototype.$get = function(id) {
            CreditCard.$get.call(this, id);
        };

        return CreditCard;

    }

    return CreditCardFactory;

}]);

然后,在您的控制器函数中,像使用 $resource 一样注入 CreditCard 工厂。

app.controller('CreditCardCtrl', function($scope, CreditCard) {
    $scope.creditCard = CreditCard().get(3);
});

这允许您以任何想要的方式解析您的REST操作的响应,并且还允许您实现任何想要的操作。例如:我想在我的资源上拥有一个保存方法,该方法将检查对象是否具有ID属性,然后选择使用POST(在没有可用ID时创建新资源)或PUT(在存在有效ID时更新现有资源)。

这也允许您实现处理JSON CSRF漏洞的不同方式。Angular.js方式已经内置于$http中,但是我们公司的REST API通过在虚拟对象中包装JSON数组来解决此问题。我使用类似上面的自定义资源来解析虚拟对象。


这是一个很好的回复,Brett,谢谢。我越来越发现使用股票$resource时,希望在$http之上编写自定义包装器。 - quickshiftin
使用这种方法,您需要实现自己的save()、delete()等方法,对吗? - JBCP
如果我不将CreditCard添加为依赖项,则无法创建Creditcard()。 - Priya

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