2013-02-21 14 views
5

Ho due servizi web:AngularJS conciliano risposte del servizio web

si ritorna "Articoli" come questo:

[ 
    { 
     "id": "1", 
     "headline": "some text", 
     "body": "some text", 
     "authorId": "2" 
    }, 
    { 
     "id": "2", 
     "headline": "some text", 
     "body": "some text", 
     "authorId": "1" 
    } 
] 

e l'altro restituisce un "autore" come questo, dato un id:

{ 
    "id": "1", 
    "name": "Test Name", 
    "email": "[email protected]", 
    "photo": "path/to/img" 
} 

Desidero combinare i due, in modo da poter visualizzare il nome e la foto degli autori in un elenco di panoramica degli articoli.

Ti piace questa:

[ 
    { 
     "id": "1", 
     "headline": "some text", 
     "body": "some text", 
     "authorId": "2", 
     "author_info": { 
      "id": "2", 
      "name": "Another Test Name", 
      "email": "[email protected]", 
      "photo": "path/to/img" 
     } 
    }, 
    { 
     "id": "2", 
     "headline": "some text", 
     "body": "some text", 
     "authorId": "1" 
     "author_info": { 
      "id": "1", 
      "name": "Test Name", 
      "email": "[email protected]", 
      "photo": "path/to/img" 
     } 
    } 
] 

Ho un servizio di "articoli" che recupera gli articoli, ma qual è l'approccio migliore per arricchire il JSON restituita con le informazioni dell'autore dai simili "Autori" di servizio prima di tornare al Output del servizio "Articoli"?

factory('Authors', ['$http', function($http){ 
    var Authors = { 

     data: {}, 

     get: function(id){ 
      return $http.get('/api/authors/' + id + '.json') 
       .success(function(data) { 
        Authors.data = data; 
       }) 
       .error(function() { 
        return {}; 
       }); 
     } 
    }; 

    return Authors; 
}]). 

factory('Articles', ['$http', 'Authors', function($http, Authors){ 
    var Articles = { 

     data: {}, 

     query: function(){ 
      return $http.get('/api/articles.json') 
       .success(function(result) { 
        Articles.data = result; // How to get the author info into this JSON object??? 
       }) 
       .error(function() { 
        Articles.data = []; 
       }); 
     } 
    }; 
    return Articles; 
}]) 

Per favore, dimmi se questo è un approccio completamente sbagliato. :)

risposta

0

Un'opzione consiste nel combinare tutti questi dati sul server, magari creando un file json separato. Ciò semplificherà il lato client e richiederà solo una richiesta HTTP invece di due.

Se si stanno mantenendo entrambi i servizi (che non è un approccio errato) si potrebbe licenziare uno, attendere la risposta e sparare il secondo. Forse fare la prima Articles e poi il Authors:

Articles.get(function (articles) {     
      $scope.articles = articles; 
      //fire query for Authors 
      Authors.query(function (authors) { 
       $scope.authors= authors; 
       //combine both articles and authors 
       combineData(articles, authors);      
      }) 
}); 

Ecco la funzione che combina i dati:

function combineData(articles, authors){ 
    $.each(articles, function (i, article) { 
     //find author 
     var author = $.grep(authors, function(a, j){ 
        return a.id == article.authorId; 
        }); 
     //set article's author 
     article.author_info = author; 
    }); 
} 

Si noti che con questa configurazione i tuoi articoli renderanno (impostando $scope.articles) anche prima di effettuare la chiamata a Authors.query

+0

Grazie per il consiglio, ma questo significherebbe andare a prendere tutti gli autori su ogni articolo, giusto? Questo è un sacco di traffico. –

+0

No, il codice presuppone che è possibile recuperare tutti gli articoli e al termine si prenderà TUTTI gli autori. Quindi combinare i risultati. Sono coinvolte solo due richieste – Ulises

+0

@ JakobLøkkeMadsen l'hai scoperto? – Ulises

6

Quando si comunica con l'API, si consiglia il seguente approccio per strutturare il proprio rvizi (come advised by Misko Hevery):

// Author model/service 
    angular.module('myApp').factory('Author', function($http) { 
     var Author = function(data) { 
     angular.extend(this, data); 
     }; 

     Author.get = function(id) { 
     return $http.get('/authors/' + id).then(function(response) { 
      return new Author(response.data); 
     }); 
     }; 

     return Author; 
    }); 

    // Article model/service 
    angular.module('myApp').factory('Article', function($http) { 
     var Article = function(data) { 
     angular.extend(this, data); 
     }; 

     Article.query = function() { 
     return $http.get('/articles/').then(function(response) { 
      var articles = []; 
      angular.forEach(response.data, function(data){ 
      articles.push(new Article(data)); 
      }); 
      return articles; 
     }); 
     }; 

     return Article; 
    }); 

    // Your controller 
    angular.module('myApp') 
     .controller('Ctrl' 
     ,[ 
      '$scope' 
      ,'Article' 
      ,'Author' 
      ,function($scope, Article, Author){ 
      Article.query() 
       .then(function(articles){ 
       $scope.articles = articles; 
       attachAuthors(articles); 
       }); 

      function attachAuthors(articles){ 
       angular.forEach(articles, function(article){ 
       Author.get(article.authorId) 
        .then(function(author){ 
        article.author = author; 
        }); 
       }); 
      } 

      } 
     ] 
    ); 

ma di sicuro, vorrei anche consigliare contro il recupero di tutti questi dati in chiamate separate. Invece, se possibile, dovresti avere la tua API che ti restituisce il JSON combinato. La combinazione lato server sarebbe molte volte più veloce.

+1

Grazie per il consiglio + il link alla risposta di Misko. Molto informativo. –

2

Scopri JSOG. È perfetto per fare questo genere di cose. Esistono attualmente implementazioni server per Java, Python, Javascript e Ruby. Sul lato javascript del client, è sufficiente chiamare JSOG.decode (oggetto). Lo uso pesantemente con Angular.

https://github.com/jsog/jsog

+0

Hey @ jon-stevens, hai detto che usi jsog pesantemente con AngularJS, puoi dire come lo fai? –

+1

@JayrMotta Grazie per avermelo chiesto! È piuttosto semplice, si 'decodifica = JSOG.decode (dati)', dove 'data' è la risposta del corpo dalla richiesta ajax. Nel caso di angolare, lo faccio nella promessa '.success()' per $ http o all'interno di un intercettore. –

+0

Ho fatto questo per poter lavorare a livello globale prima del testo JSON è stato derialized: 'javascript $ httpProvider.defaults.transformResponse.splice (0, 0, funzione (dati' ', headersGetter) { se (i dati && headersGetter () ['content-type'] === 'application/json') { return JSOG.parse (data); } else { dati di ritorno; } }); '' ' Cosa ne pensi? –