2013-06-16 22 views
36

Trong hầu hết các trường hợp, các kết quả của <custom-resource>.query() phương pháp là một mảng, có thể dễ dàng mở rộng với một số phương pháp (logic kinh doanh) như sau (nhà máy) mã:

var Data = $resource('http://..'); 
Data.prototype.foo = function() {return ...}; 

này là hoàn hảo cho sử dụng với ng-repeat/ng-class, như vậy:

<tr ng-repeat="item in responseData" ng-class="{warning: item.foo()}">..</tr> 

vấn đề của tôi là mỗi phản ứng danh sách được đóng gói trong một đối tượng đó, bên cạnh những danh sách thực tế, có một số meta- tính chất (sắp xếp thông tin, vv), vì vậy đối tượng cuối cùng được trả lại là như sau:

{ order_field: "name", items: [{..}, {..},{..}] } 

Bây giờ, làm cách nào để làm điều tương tự như trước đây với ng-repeat/ng-class?

<tr ng-repeat="item in responseData.items" ng-class="????">..</tr> 

các phương pháp trước đó sẽ không làm việc như là phương pháp "foo" được định nghĩa trên responseData và NOT trên item đối tượng

Có cách nào để trực tiếp mở rộng các lớp cơ sở sử dụng cho instantiating đối tượng trong danh sách ?

Cảm ơn!

Trả lời

52

Tôi đã tìm thấy vấn đề đó trước đây và giải pháp có vẻ là transformResponse, như John Ledbetter nói trong câu trả lời khác.

Dù sao, nếu bạn cần phải giữ cho toàn bộ đối tượng, và cũng có mảng trong 'mục' tràn ngập trường hợp của tài nguyên, bạn có thể có thể làm điều đó với cách lừa sau:

Lấy ví dụ từ câu trả lời của John và sửa đổi nó một chút:

angular.module('foo') 

    .factory('Post', ['$resource', function($resource) { 

    var Post = $resource('/api/posts/:id', { id: '@id' }, { 
     query: { 
     method: 'GET', 
     isArray: false, // <- not returning an array 
     transformResponse: function(data, header) { 
      var wrapped = angular.fromJson(data); 
      angular.forEach(wrapped.items, function(item, idx) { 
      wrapped.items[idx] = new Post(item); //<-- replace each item with an instance of the resource object 
      }); 
      return wrapped; 
     } 
     } 
    }); 

    Post.prototype.foo = function() { /* ... */ }; 

    return Post; 
    }]); 
+1

Tôi nghĩ đây là một giải pháp vững chắc. Nó không cảm thấy _perfect_ với tôi, nhưng nó là tốt nhất tôi đã nhìn thấy :) –

+0

Cảm ơn bạn đã trả lời này. –

9

Nếu bạn đang sử dụng góc tài nguyên 1.1.5 (mà như xa như tôi có thể nói thực sự hoạt động tốt với 1.0.7 góc), có một tùy chọn transformResponse bạn có thể chỉ định khi trọng $resource phương pháp:

angular.module('foo') 
    .factory('Post', ['$resource', function($resource) { 

    var Post = $resource('/api/posts/:id', { id: '@id' }, { 
     query: { 
     method: 'GET', 
     isArray: true, 
     transformResponse: function(data, header) { 
      var wrapped = angular.fromJson(data); 
      return wrapped.items; 
     } 
     } 
    }); 

    Post.prototype.foo = function() { /* ... */ }; 

    return Post; 
    }]); 

Nếu bạn làm điều này, bạn không còn phải tự kéo các mục ra khỏi phản hồi được bao bọc và mỗi mục sẽ là một phiên bản Post có quyền truy cập vào phương thức .foo. Bạn chỉ có thể viết:

<tr ng-repeat="post in posts" ng-class="{warning: post.foo()}">..</tr> 

Nhược điểm của việc này là bạn mất quyền truy cập vào bất kỳ trường bên ngoài nào trong phản hồi không nằm trong các mục. Tôi vẫn đang đấu tranh để tìm ra cách để bảo vệ siêu dữ liệu đó.

+0

cảm ơn, nhưng đây không thực sự là những gì tôi đang tìm kiếm. Khi tôi đang viết cả frontend-js frontend và C# -backend, tôi có thể đơn giản tránh việc gói các danh sách trong đối tượng, nhưng vấn đề là tôi cũng cần siêu dữ liệu đó. – migajek

+1

@migajek Tôi hiểu, tôi đang ở trong tình huống tương tự - Tôi muốn có thể hỗ trợ phân trang/sắp xếp với API của tôi mà không cần phải 'thủ công' tất cả các tài nguyên. Hãy quan tâm để xem nếu có bất kỳ câu trả lời tốt cho điều này. –

+0

Tôi thêm siêu dữ liệu trở lại bằng cách thêm biến đóng cửa chức năng() { var meta = {}; var Product = $ resource = {tranformResponse: function (data) { meta.prop = data.prop;} } Product._meta = meta; sản phẩm trả lại; } – ebt

4

Đây là câu hỏi cũ, nhưng tôi chỉ tự mình gặp vấn đề này. giải pháp của gargc là cách tiếp cận đúng, nhưng có một sự cải tiến. transformResponse chấp nhận một mảng được chuyển đến dịch vụ $http. Thay vì thay thế hoàn toàn biến đổi chức năng, bạn có thể thêm chuyển đổi của bạn để giá trị mặc định chỉ cần thực hiện các bản cập nhật bạn cần:

angular.module('foo') 
    .factory('Post', function ($resource, $http) { 
     var Post = $resource('/api/posts/:id', { id: '@id' }, { 
      query: { 
       method: 'GET', 
       isArray: false, 
       transformResponse: $http.defaults.transformResponse.concat(function(data, header) { 
        angular.forEach(data.items, function(item, idx) { 
         data.items[idx] = new Post(item); 
        }); 
        return data; 
       }) 
      } 
     }); 

     Post.prototype.foo = function() { /* ... */ }; 

     return Post; 
    }); 
0

Bạn có thể đặt các siêu dữ liệu trong một tiêu đề. Tôi luôn đặt dữ liệu phân trang ở đó.Bằng cách đó truy vấn của bạn sẽ vẫn trả về một mảng, mà tôi tin là một điều tốt. Truy vấn sẽ trả về mảng dữ liệu, không phải dữ liệu đơn lẻ.

Các vấn đề liên quan