2013-02-21 9 views
5

ich zwei Web-Services haben:AngularJS kombiniert Web-Service-Antworten

Eine Rückkehr "Artikel" wie folgt aus:

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

Und der andere gibt ein "Autor" wie diese, eine ID gegeben:

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

Ich möchte die beiden kombinieren, damit ich den Namen und das Foto des Autors in einer Artikelübersichtsliste anzeigen kann.

So:

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

Ich habe einen „Artikel“ Service, der die Artikel holt, aber was ist der beste Ansatz für die zurückgegebene JSON mit dem Autor Informationen aus den ähnlichen „Autoren“ Service bereichern, bevor die Rückkehr "Artikel" Service-Ausgabe?

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

Bitte sagen Sie mir auch, wenn das ein völlig falscher Ansatz ist. :)

Antwort

0

Eine Option besteht darin, all diese Daten auf dem Server zu kombinieren und möglicherweise eine separate JSON-Datei zu erstellen. Dies vereinfacht die Client-Seite und erfordert nur eine HTTP-Anfrage statt zwei.

Wenn Sie beide Dienste halten (was kein schlechter Ansatz ist), könnten Sie einen auslösen, auf die Antwort warten und den zweiten auslösen. Vielleicht tun die Articles zuerst und dann die 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);      
      }) 
}); 

Hier kann die Funktion ist, dass die Daten kombiniert:

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

Beachten Sie, dass mit dieser Konfiguration Ihre Artikel (indem $scope.articles) machen sogar vor dem Anruf Authors.query

+0

Danke für den Rat, aber auf jedem Artikel alle Autoren holen würde bedeuten, nicht wahr? Das ist viel Verkehr. –

+0

Nein, der Code geht davon aus, dass Sie alle Artikel abrufen können und nach Fertigstellung ALLE Autoren holen. Kombiniere dann die Ergebnisse. Nur zwei Anfragen sind beteiligt – Ulises

+0

@ JakobLøkkeMadsen hast du es herausgefunden? – Ulises

6

Bei der Kommunikation mit API würde ich den folgenden Ansatz zur Strukturierung Ihrer Se empfehlen rvices (als 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; 
        }); 
       }); 
      } 

      } 
     ] 
    ); 

Aber sicher, würde ich raten, auch in getrennten Gesprächen all diese Daten gegen holen. Stattdessen sollten Sie, wenn möglich, Ihre API den kombinierten JSON zurückgeben lassen. Das serverseitige Kombinieren wäre um ein Vielfaches schneller.

+1

Danke für den Hinweis + den Link zu Miskos Antwort. Sehr informativ. –

2

Überprüfen Sie JSOG. Es ist perfekt für diese Art von Sachen. Derzeit gibt es Serverimplementierungen für Java, Python, Javascript und Ruby. Auf der Javascript-Seite des Clients rufen Sie einfach JSOG.decode (Objekt) auf. Ich benutze es stark mit Angular.

https://github.com/jsog/jsog

+0

Hey @ jon-stevens, du hast gesagt, dass du jsog stark mit AngularJS benutzt, kannst du sagen, wie du das machst? –

+1

@JayrMotta Danke für die Nachfrage! Es ist ziemlich einfach, Sie haben nur 'decodiert = JSOG.decode (Daten)', wobei 'Daten' die Antwort des Körpers von Ihrer Ajax-Anfrage ist. Im Fall von eckig mache ich dies in der '.success()' Versprechung für $ http oder innerhalb eines Interceptors. –

+0

Ich tat dies, um global zu arbeiten, bevor die json Text derialized wurde: '' 'javascript $ httpProvider.defaults.transformResponse.splice (0, 0, Funktion (Daten, headersGetter) { if (Daten && headersGetter () ['Inhaltstyp'] === 'Anwendung/Json') { Rückgabe JSOG.parse (Daten); } sonst { Rückgabedaten; } }); '' ' Was denkst du? –