Note that there are some explanatory texts on larger screens.

plurals
  1. POAngularJS and complex JSON returned by django tastypie
    primarykey
    data
    text
    <p>I have few resources written on AngularJS that access a Tastypie API. Everything works fine, except for a detail: tastypie always encapsulate the actual result inside a <code>objects</code> attribute on a JSON, example:</p> <p><code>/api/v1/reminder/</code>:</p> <pre><code>{ meta: { limit: 20, next: null, offset: 0, previous: null, total_count: 3 }, objects: [{ category: { color: "#999999", id: 1, name: "Groceries", resource_uri: "/api/v1/category/1" }, description: "", due_date: "2010-10-16", id: 1, repeat: "weekly", resource_uri: "/api/v1/reminder/1", value: "-50" }, { category: { color: "#999999", id: 1, name: "Groceries", resource_uri: "/api/v1/category/1" }, description: "", due_date: "2010-10-17", id: 2, repeat: "weekly", resource_uri: "/api/v1/reminder/2", value: "-50" } } </code></pre> <p>It was wasy to fix using a callback to the <code>get()</code> call:</p> <pre><code>Reminder.get().$then(function (result) { $scope.reminders = result.data.objects; }); </code></pre> <p>But I know <code>result.resource</code> is an actual <code>Reminder</code> instance.</p> <pre><code>.factory('Reminder', ['$resource', function($resource){ var Reminder = $resource('/api/v1/reminder/:id', {}, { get: { method: 'GET', isArray: false } }); Reminder.prototype.TESTE = function () {console.log('asd');}; return Reminder; }]) </code></pre> <p>Now I need to implement behavior on my <code>Reminder</code> class, and I need every element on my <code>meta.objects</code> to be an instance of <code>Reminder</code>:</p> <pre><code>Reminder.get().$then(function (result) { $scope.reminders = result.data.objects; result.resource.TESTE(); // -&gt; outputs 'asd' o = result.data.objects[0]; o.TESTE // -&gt; undefined, obvisously i = new Reminder(o); i.TESTE() // -&gt; outputs 'asd' }); </code></pre> <p>So, how to I get angularjs to understand that every object on <code>objects</code> is the actual result so it behaves like a list of instances?</p> <p>The workaround is to creating a new list iterating on the results creating the instances, but it's not optimal...</p> <p>Suggestions?</p> <h1>Solution by @rtcherry:</h1> <p>As suggested by rtcherry, I used <a href="https://github.com/mgonto/restangular" rel="noreferrer">restangular</a></p> <p>Configuring the reading of request data:</p> <pre><code>.config(['RestangularProvider', function(RestangularProvider) { RestangularProvider.setBaseUrl("/api/v1"); RestangularProvider.setResponseExtractor(function(response, operation, what, url) { var newResponse; if (operation === "getList") { newResponse = response.objects; newResponse.metadata = response.meta; } else { newResponse = response.data; } return newResponse; }); }]) </code></pre> <p>Loading the reminders:</p> <pre><code>function RemindersCtrl ($scope, $rootScope, Reminder) { $scope.reminders = Reminder.getList(); } </code></pre> <p>Adding my custom method to <code>Reminder</code> (not as clean as ngResource, but doable):</p> <pre><code>.factory('Reminder', ['Restangular', '$filter', function(Restangular, $filter){ var Reminder = Restangular.all('reminder'); var remainingDays = function () { //do stuff }; // adding custom behavior Restangular.addElementTransformer('reminder', false, function (reminder) { reminder.remainingDays = remainingDays; return reminder; }); return Reminder; }]) </code></pre> <h1>Solution by @moderndegree:</h1> <p>I used pure <code>ngResource</code>:</p> <pre><code>var tastypieDataTransformer = function ($http) { return $http.defaults.transformResponse.concat([ function (data, headersGetter) { var result = data.objects; result.meta = data.meta; return result; } ]) }; ... .factory('Reminder', ['$resource', '$http', function($resource, $http){ var Reminder = $resource('/api/v1/reminder/:id', {}, { query: { method: 'GET', isArray: true, transformResponse: tastypieDataTransformer($http) } }); Reminder.prototype.remainingDays = function () { // doing stuff }; return Reminder; }]) </code></pre> <p>My controller:</p> <pre><code>Transaction.query(filter).$then(function (result) { $scope.days = []; var transactions = result.resource; resource[0].remainingDays(); // it works }); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload