【问题标题】:Virtual attributes in ngResourcengResource 中的虚拟属性
【发布时间】:2014-07-25 03:37:32
【问题描述】:

是否可以向 ngResource 添加虚拟属性? 我创建了这样的服务

app.factory('Person', ['$resource', function($resource) {

  return $resource('api/path/:personId', {
    personId: '@_id'
      }, {
        update: {
          method: 'PUT'
        }
      });
}])

Person 有一个属性name 和一个属性surname
我想通过添加虚拟属性 fullname 返回 resource.name + resource surname 来检索 fullname
我知道我可以将它添加到控制器中,但是将它添加到服务中会使其更便携。 我试过这样的东西

app.factory('Person', ['$resource', function($resource) {

  return $resource('api/path/:personId', {
    personId: '@_id'
      }, {
        update: {
          method: 'PUT'
        },
    fullname: function(resource){
      return resource.name + ' ' + resource.surname;
    }
  });
 });
}])

但它不起作用。

【问题讨论】:

    标签: angularjs ngresource


    【解决方案1】:

    Khanh TO 让我找到了可行的答案,但是,正如in this Angular ticket 所解释的,在拦截器中,您必须处理并返回response.resource 而不是response

    这是一个解决方案(适用于 Angular 1.4):

    app.factory('Person', ['$resource', function($resource) {
    
    return $resource(
        'api/path/:personId',
        {personId: '@_id'},
        {
            update: {method: 'PUT'},
            get: {
                method: 'GET',
                isArray: false,
                interceptor: {
                    response: function(response) {
                        var resource = response.resource;
                        resource.fullname = resource.name + ' ' + resource.surname;
                        return resource;
                    }
                }
            }
        });
    }]);
    

    【讨论】:

      【解决方案2】:

      您可以尝试 intercepting 来自 Person 资源的响应并增加响应。像这样:

      app.factory('Person', ['$resource', function($resource) {
        function getFullName(){
            return this.name + ' ' + this.surname;
        };
      
        return $resource('api/path/:personId', {
          personId: '@_id'
            }, {
              update: {
                method: 'PUT'
              },
              'get': {method:'GET', isArray:false,interceptor:{
                    'response': function(response) {
                        response.fullname = getFullName; //augment the response with our function
                        return response;
                     }
               }}
            });
      }]);
      

      【讨论】:

        【解决方案3】:

        如果您只需要派生属性进行显示,您可以创建一个显示过滤器,而不是用冗余数据加载您的模型:

        app.filter('personFullName', function() {
          return function(person) {
            return person.name + " " + person.surname;
          };
        })
        

        然后在你的模板中引用过滤器:

        <div>
          <p>{{person | personFullName}}</p>
          <p>- should match -</p>
          <p>{{person.name}} {{person.surname}}</p>
        </div>
        

        【讨论】:

        • 这个解决方案很有趣,但我想我更愿意将虚拟属性保留在模型中,这样我就可以在多个视图中访问它,而不必处理每个视图中的过滤器。
        【解决方案4】:

        根据文档,$resource 返回一个构造函数。您可以利用构造函数的常用prototype 添加成员,即:

        var Person = $resource('api/path/:personId', {
                    personId: '@_id'
                }, {
                    update: { method: 'PUT' }
                }); // same as the 1st snippet from the question
        
        Person.prototype.xxxx = ...;
        
        return Person; // from your Angular service
        

        在前面的示例中,xxxx 可以是原型中通常允许的任何内容。如果您想要的实际上是派生属性,即始终反映namesurname 属性的JS 属性,那么您需要一个支持Object.defineProperty() 的相当新的浏览器并将上面的Person.prototype 行替换为:

        Object.defineProperty(
            Person.prototype,
            "fullname",
            {get: function() { return this.name + " " + this.surname; }}
        );
        

        【讨论】:

        • 它像任何其他属性一样工作,但你不能为它设置值(除非你指定一个 setter)
        • 当然不是,也不应该,因为这是一个派生(计算)的属性。如果其他用例需要,可以定义一个 setter。
        • 我不是不同意你的观点^^,只是想澄清一下。
        • 这看起来不错,但我想看看是否有人有更“棱角分明”的解决方案。
        • 有角度的方法是像在那个 plunk 中所做的那样转换响应:jsfiddle.net/roadprophet/YpvG7
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多