2013-06-26 12 views
10

Ho poche risorse scritte su AngularJS che accedono a un'API Tastypie. Tutto funziona bene, tranne che per un dettaglio: tastypie incapsulare sempre il risultato reale all'interno di un attributo objects su un JSON, ad esempio:AngularJS e JSON complesso restituito da django tasteypie

/api/v1/reminder/:

{ 
    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" 
    } 
} 

Era wasy per fissare utilizzando un callback per la chiamata get() :

Reminder.get().$then(function (result) { 
    $scope.reminders = result.data.objects; 
}); 

Ma so result.resource è un vero e proprio Reminder esempio.

.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; 
}]) 

Ora ho bisogno di implementare un comportamento su mia classe Reminder, e ho bisogno ogni elemento sul mio meta.objects ad essere un'istanza di Reminder:

Reminder.get().$then(function (result) { 
    $scope.reminders = result.data.objects; 

    result.resource.TESTE(); // -> outputs 'asd' 

    o = result.data.objects[0]; 
    o.TESTE // -> undefined, obvisously 
    i = new Reminder(o); 
    i.TESTE() // -> outputs 'asd' 
}); 

Quindi, come ottengo angularjs a capire che ogni oggetto su objects è il risultato effettivo quindi si comporta come un elenco di istanze?

La soluzione è la creazione di un nuovo elenco iterazione sui risultati che creano le istanze, ma non è ottimale ...

Suggerimenti?

Solution di @rtcherry:

Come suggerito da rtcherry, ho usato restangular

Configurazione della lettura della richiesta dei dati:

.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; 
    }); 
}]) 

Caricamento dei promemoria:

function RemindersCtrl ($scope, $rootScope, Reminder) { 
    $scope.reminders = Reminder.getList(); 
} 

Aggiungere il mio metodo personalizzato a Reminder (n ot pulito come ngResource, ma fattibile):

.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; 
}]) 

Solution di @moderndegree:

ho usato puro ngResource:

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; 
}]) 

mio regolatore:

Transaction.query(filter).$then(function (result) { 
    $scope.days = []; 
    var transactions = result.resource; 
    resource[0].remainingDays(); // it works 

}); 
+1

Si consiglia di provare qualcosa come [restangular] (https://github.com/mgonto/restangular). – rtcherry

+0

whoa, sembra buono .. lo esaminerò –

+0

fatto. non è facile come aggiungere un metodo a una risorsa angolare, ma può essere fatto ... ma restangular ripaga su molte funzioni utili. vuoi fare una risposta dal tuo commento in modo che io possa contrassegnarlo? –

risposta

6

Se si voleva evitare di utilizzare una libreria aggiuntiva, si dovrebbe essere in grado di effettuare le seguenti operazioni:

$resource('/api/v1/reminder/', {}, { 
    query: { 
     method: 'GET', 
     isArray: true, 
     transformResponse: $http.defaults.transformResponse.concat([ 
      function (data, headersGetter) { 
       return data.objects; 
      } 
     ]) 
    } 
}); 

Questo aggiungerà la vostra trasformazione per trasformatore predefinito $HttpProvider s'.

Nota: Correggimi se ho torto su questo, ma credo che questa funzione richieda la versione 1.1 o successiva.

+1

+1 per pubblicare una soluzione che utilizza le nuove funzionalità 'ngResource' dal ramo 1.1.x di AngularJS. – rtcherry

+0

ho intenzione di provarlo! sto avendo qualche problema con restangular non mi dà la risposta su una richiesta di posta, e ha funzionato su ngresource. tornare al più tardi mi avrebbe risparmiato un po 'di tempo. –

+1

Fresco. È sempre utile limitare il numero di librerie da caricare. Inoltre, ecco una risposta che ho postato di recente che ha risolto un problema simile. http://stackoverflow.com/questions/17332922/how-can-i-insert-commands-before-or-prevent-https-jsonp-automatic-parsing-in-a/17333030#17333030 @Shaman stava cercando un modo per trasformare la risposta prima della trasformazione predefinita. –

4

Si può vuoi provare qualcosa come restangular.

C'è qualche configurazione necessaria per farlo funzionare. Un esempio è here.

+0

aggiornerò la mia domanda più tardi con il codice della soluzione. –

3

Ho finito col fare quanto segue per conservare l'oggetto meta direttamente sui risultati restituiti da Reminder.query() (espandendo la risposta da @moderndegree).

var Reminder = $resource('/api/v1/reminder/', {}, { 
    query: { 
    method: 'GET', 
    isArray: true, 
    transformResponse: $http.defaults.transformResponse.concat([ 
     function (data, headersGetter) { 
      return data.objects; 
     } 
    ]), 
    interceptor: { 
     response: function(response) { 
     response.resource.meta = response.data.meta; 
     } 
    } 
    } 
}); 

che permette di ottenere il valore meta direttamente sul oggetto restituito:

var reminders = Reminder.query(...); 
console.log(reminders.meta); // Returns `meta` as expected. 

penso che sarebbe anche possibile fare qualcosa di simile all'interno della richiamata da Reminder.query poiché l'oggetto response è disponibile anche lì.