简体   繁体   English

angular 1.5 $ resource,如何为所有请求设置默认动作(例如transformResponse)?

[英]angular 1.5 $resource, how to set default action, (e.g. transformResponse) for all requests?

i have a resource like: 我有像这样的资源:

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  return $resource('/something', {}, {
    find  : {method: 'GET', isArray: true, transformResponse: convertFn},
    create: {method: 'POST', isArray: true, transformResponse: convertFn},
    update: {method: 'PUT', isArray: true, transformResponse: convertFn},
  });

  function convertFn(){
    //...
  }

}

is it possible to not to copypaste the transformResponse in every type of request? 是否可以不在每种类型的请求中都复制粘贴transformResponse? Define some default transformResponse? 定义一些默认的transformResponse吗?

possible solution just to modify the definition object by adding the property programmatically, but such solution looks hard to maintain. 可能的解决方案只是通过以编程方式添加属性来修改定义对象,但这种解决方案看起来很难维护。

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  var types = {
    find  : {method: 'GET', isArray: true},
    create: {method: 'POST', isArray: true},
    update: {method: 'PUT', isArray: true},
  }

  //add transform to each, es6
  Object.keys(types).forEach(k => types[k].transformResponse = convertFn)

  return $resource('/something', {}, types);

  function convertFn(){
    //...
  }

}

edit 编辑
thx to georgeawg for the idea 谢谢乔治的想法
another way could be: write a wrapper function for defaults like: 另一种方法可能是:为默认值编写包装函数,例如:

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  var types = {
    find  : defaults({method: 'GET'}),
    create: defaults({method: 'POST', isArray: false}),
    update: defaults({method: 'PUT'}),
  }

  return $resource('/something', {}, types);

  function convertFn(){
    //...
  }

  function defaults(opts) {
    return Object.assign({
      isArray: false,
      transformResponse: convertFn
    }, opts)
  }

}

is there some cleaner solution for it? 是否有一些更清洁的解决方案?

How about: 怎么样:

angular.module('mymodule')
    .factory('someResource', someResource);

function someResource($resource) {
  return $resource('/something', {}, {
    find  : action('GET'),
    create: action('POST'),
    update: action('PUT')
  });

  function action(method) {
      return { method: method,
               isArray: true,
               transformResponse: convertFn
              };
  }

  function convertFn(){
    //...
  }

}

Using a Response Interceptor 使用响应拦截器

Since the $resource uses the $http service under the hood, a response interceptor can transform responses: 由于$resource$http使用$http服务,因此响应拦截器可以转换响应:

app.config(function($httpProvider) {
    $httpProvider.interceptors.push(function() {
      return {
       'request': function(config) {
           //
        },

        'response': function(response) {
          if (response.config.url.startsWith("/something") {
              response.data = convertFn(response.data);
          };
          return response;

          function convertFn(data) {
             //return new data
          }
        }
    });
});

Have you looked at angular $http interceptors ? 您是否看过有角度的$ http拦截器 ngResource would honor a response interceptor function. ngResource将采用响应拦截器功能。 Here's a post that details usage. 是详细说明用法的帖子

It is possible to have a very generic base $resource and inherit it. 可以有一个非常通用的基础$ resource并继承它。

I found the answer on a SO post that i can't found anymore. 我在找不到的SO帖子上找到了答案。 If someone found it edit my post to add it. 如果有人找到它,请编辑我的帖子以添加它。

Here is the code that I use : 这是我使用的代码:

angular.baseResourceServiceMaker = function(service){
    return ['$injector', '$resource', 'TypeService', '$http', '_', 'BackEndpoint', 'Utils',
            function($injector, $resource,TypeService, $http, _, BackEndpoint, Utils){
        this.restUrl = BackEndpoint+'/rest/';
        this.baseName = '';
        this.resource = null;
        // from angular-resource
        var toString= function() {
            var value = [];
            _.forEach(this, function(e) {
                value.push('' + e);
                });
            return '[' + value.join(', ') + ']';
          };
          var isObject = function isObject(value) {
              // http://jsperf.com/isobject4
              return value !== null && typeof value === 'object';
            };
        var isFile = function(obj) {
          return toString.call(obj) === '[object File]';
        }


        var isFormData = function(obj) {
          return toString.call(obj) === '[object FormData]';
        }


        var isBlob = function(obj) {
          return toString.call(obj) === '[object Blob]';
        }
        this.defaultToJson = function(d) {
              return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? angular.toJson(d) : d;
        };
        this.typeServiceProcessData = function(d){
            return TypeService.processData(d);
        };
        this.typeServiceProcessJsData = function(d){
            return TypeService.processJsData(d);
        };
        this.generateTransformRequestFn = function(mapKeyValues){
            return function(data){
                var object = {};
                _.forEach(_.keys(mapKeyValues), function(key){
                    Utils.setAttributeValue(object, key, Utils.getAttributeValue(data, mapKeyValues[key]));

                });
                return object;
            }
        };

        this.addedMethods = {};
        // use of resource will be internal, to handle transformation of data
        // and so on...
        this.getResource = function(){
            if(this.resource == null){
                var baseResourceUrl = this.restUrl + this.baseName + '/';
                var baseResourceMethods = {
                        'get':      {method:'GET', transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData],
                            url:baseResourceUrl+':id'},
                        'create':   {method:'POST', url:baseResourceUrl, transformRequest:[this.typeServiceProcessJsData, this.defaultToJson]},
                        'update' :  {method:'PUT', transformRequest:[this.typeServiceProcessJsData, this.defaultToJson]},
                        'search':   {method:'GET', isArray:true, transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
                            url:baseResourceUrl+'search/(:search)/:offset/:limit/:order',
                            params: {offset:0, limit:50, order:"creationDate=asc"}
                        },
                        'custom_search':    {method:'GET', isArray:true, transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
                            url:baseResourceUrl+':prefix/search/(:search)/:offset/:limit/:order',
                            params: {search:'pk=gt=0',offset:0, limit:50, order:"creationDate=asc"}
                        },
                        'list':     {method:'GET', isArray:true, transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
                            url:baseResourceUrl+'search/(pk=gt=0)/0/50/creationDate=asc'
                        },

                        'delete':   {method:'DELETE'} 
                    };
                _.forEach(_.keys(this.addedMethods), function(key){
                    baseResourceMethods[key] = this.addedMethods[key];
                }, this)
                this.resource = $resource(baseResourceUrl+':id',
                    {id:'@pk'}, baseResourceMethods
                    );
            }
            return this.resource;
        };
        this.get = function(id){
            this.getResource().get({id:id});
        };
        this.create = function(data){
            this.getResource().create(data);
        };
        this.update = function(data){
            this.getResource().update(data);
        };
        this.search = function(searchQuery){
            this.getResource().search({search:searchQuery});
        };
        this.searchPaginate = function(searchQuery, offset, limit){
            this.getResource().search({search:searchQuery, offset:offset, limit:limit});
        };
        this['delete'] = function(id){
            this.getResource()['delete']({id:id});
        };
           // Finishes the other injections
        $injector.invoke(service, this);

    }];
};

Some comments about this code : 关于此代码的一些注释:

  • The functions isFile/isObject,... are c/c from angular.js because I keep the defaultTransformResponse from angularJS, this function use internal function that are not in my scope so I had to cc it. 函数isFile / isObject,...是angular.js的c / c,因为我保留了angularJS的defaultTransformResponse,此函数使用不在我范围内的内部函数,因此我必须对其进行cc。
  • I define default methods create/update/... 我定义默认方法创建/更新/ ...
  • I have a typeService where i declare all my type and fields, so i can automatically convert type : for instance my server's date are always timestamps, so i convret it automatically to Javascript Date in transformResponse and the opposite in transformRequest. 我有一个typeService,我在其中声明了所有类型和字段,因此我可以自动转换类型:例如,我的服务器的日期始终是时间戳记,因此我将其自动转换为transformResponse中的Javascript Date,而将其转换为transformRequest中的Javascript Date。
  • addedMethods is used to add others method. addMethods用于添加其他方法。
  • restUrl is the entry point of all rest services, baseName must be set by the implementation, it's the entry point for the resource. restUrl是所有rest服务的入口点,baseName必须由实现设置,它是资源的入口点。 BackEndPoint is the constant that define the contextPath of my application. BackEndPoint是定义我的应用程序的contextPath的常量。

Example of usage : 用法示例:

.service('ArticleService',angular.baseResourceServiceMaker(['$http', function($http){
      this.baseName = 'article';
      var baseResourceUrl = this.restUrl + this.baseName + '/';
      this.addedMethods.root ={
              method:'GET', isArray:true, 
              transformResponse:[$http.defaults.transformResponse[0], this.typeServiceProcessData], 
              url:baseResourceUrl+'root'
      };
}]))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 初始化后设置$ resource transformResponse - Set $resource transformResponse after initialization angular - 如何从自定义transformResponse获取资源参数 - angular - how to get resource parameter from custom transformResponse 确保对多个库的Javascript支持(例如Angular 1.5,jQuery 2.2.0,ckEditor 4.x,pdfjs 1.3.91) - Ensuring Javascript support for multiple libraries (e.g. Angular 1.5, jQuery 2.2.0, ckEditor 4.x, pdfjs 1.3.91) Angular-通用图像服务与特定资源(例如,用户,图像,动物)图像服务 - Angular - Generic image service vs resource-specific (e.g., user, image, animal) image services 如何从非角度上下文(例如D3事件)触发角度变化? - How to trigger an angular change from a non-angular context e.g. from a D3 event? 如何使用Angular使用外部SDK :(例如,在SDK异步调用之后更新DOM) - How To Get Angular To Work With An External SDK: (e.g., Update DOM After SDK Async Calls) 如何在不请求外部页面的情况下重用angular-js通用标记(例如,小部件)? - How to reuse angular-js common mark up (e.g. widget) without requesting external page? 如何在 Angular Resource 中设置默认标头值? - How to set default header values in Angular Resource? 如何使用Selenium / Protractor设置HTML5 type =“date”输入字段(例如在Chrome中)? - How to set HTML5 type=“date” input fields (e.g. in Chrome) using Selenium/Protractor? 以角度重定向网址(例如website.com/username) - Redirect url (e.g. website.com/username) in angular
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM