Was ist die beste Vorgehensweise für einen AJAX-Aufruf in Angular.js?


151

Ich habe diesen Artikel gelesen: http://eviltrout.com/2013/06/15/ember-vs-angular.html

Und es sagte:

Aufgrund fehlender Konventionen frage ich mich, wie viele Angular-Projekte auf schlechten Praktiken wie AJAX-Aufrufen direkt in Controllern beruhen. Fügen Entwickler aufgrund der Abhängigkeitsinjektion Router-Parameter in Direktiven ein? Werden unerfahrene AngularJS-Entwickler ihren Code so strukturieren, dass ein erfahrener AngularJS-Entwickler dies für idiomatisch hält?

Ich $httptelefoniere gerade von meinem Angular.js-Controller. Warum ist es eine schlechte Praxis? Was ist dann die beste Vorgehensweise zum $httpTelefonieren? und warum?


12
+1 für den Verweis auf einen interessanten Beitrag zum Vergleich von Glut und Winkel.
Chandermani

Ich fragte mich das gleiche über Angular Best Practices
Dalorzo

Überprüfen Sie auch die API auf Dinge, die Sie möglicherweise übersehen haben: docs.angularjs.org/api/ng/service/$http
Christophe Roussy

Antworten:


174

EDIT: Diese Antwort konzentrierte sich hauptsächlich auf Version 1.0.X. Um Verwirrung zu vermeiden, wird es geändert, um die beste Antwort für ALLE aktuellen Versionen von Angular ab dem heutigen 05.12.2013 wiederzugeben.

Die Idee ist, einen Service zu erstellen, der ein Versprechen an die zurückgegebenen Daten zurückgibt, dieses dann in Ihrem Controller aufzurufen und das Versprechen dort zu verarbeiten, um Ihre $ scope-Eigenschaft zu füllen.

Der Service

module.factory('myService', function($http) {
   return {
        getFoos: function() {
             //return the promise directly.
             return $http.get('/foos')
                       .then(function(result) {
                            //resolve the promise as the data
                            return result.data;
                        });
        }
   }
});

Der Controller:

Behandeln Sie die then()Methode des Versprechens und holen Sie die Daten heraus. Legen Sie die Eigenschaft $ scope fest und tun Sie alles, was Sie sonst noch tun müssen.

module.controller('MyCtrl', function($scope, myService) {
    myService.getFoos().then(function(foos) {
        $scope.foos = foos;
    });
});

In-View Promise Resolution (nur 1.0.X):

In Angular 1.0.X, dem Ziel der ursprünglichen Antwort, werden Versprechen von View besonders behandelt. Wenn sie aufgelöst werden, wird ihr aufgelöster Wert an die Ansicht gebunden. Dies wurde in 1.2.X veraltet

module.controller('MyCtrl', function($scope, myService) {
    // now you can just call it and stick it in a $scope property.
    // it will update the view when it resolves.
    $scope.foos = myService.getFoos();
});

4
Nur um zu erwähnen, funktioniert dies nur, wenn Sie eine $scope.foosEigenschaft in einer Vorlage verwenden. Wenn Sie dieselbe Eigenschaft außerhalb einer Vorlage verwenden (z. B. in einer anderen Funktion), ist das dort gespeicherte Objekt immer noch ein Versprechungsobjekt.
Clark Pan

1
Ich verwende dieses Muster derzeit in einer neuen eckigen App. Ich frage mich jedoch auf einer groben Seite, wie ich auf die Eigenschaft zugreifen kann, die ich an den Bereich gebunden habe. In diesem Beispiel möchte ich die Daten von getFoos übernehmen und Änderungen an veröffentlichen es. Wenn ich versuche, auf die $ scope.foos in meinem Update zuzugreifen, habe ich das Versprechen-Objekt und nicht die Daten. Ich kann sehen, wie die Daten im Objekt selbst abgerufen werden, aber es scheint wirklich sehr, sehr hacky.ideas?
Kelly Milligan

5
@ KellyMilligan, in diesem Muster ist es die Bindung , die weiß, was mit dem Versprechen zu tun ist. Wenn Sie von einem anderen Ort aus auf das Objekt zugreifen müssen, müssen Sie .then()das Versprechen einhalten und den Wert in den Bereich $ setzen ...myService.getFoos().then(function(value) { $scope.foos = value; });
Ben Lesh

1
Nur ein Update dieser Technik, ab 1.2.0-rc.3, das automatische Entpacken von Versprechungen ist veraltet, sodass diese Technik nicht mehr funktioniert.
Clark Pan

2
Ich habe hier kürzlich ein paar Abstimmungen erhalten, vermutlich weil es nicht mehr mit der neuesten Version von Angular übereinstimmt. Ich habe die Antwort aktualisiert, um dies widerzuspiegeln.
Ben Lesh

45

Die beste Vorgehensweise besteht darin, den $httpAufruf in einen "Dienst" zu abstrahieren, der Ihrem Controller Daten bereitstellt:

module.factory('WidgetData', function($http){
    return {
        get : function(params){
            return $http.get('url/to/widget/data', {
                params : params
            });
        }
    }
});

module.controller('WidgetController', function(WidgetData){
    WidgetData.get({
        id : '0'
    }).then(function(response){
        //Do what you will with the data.
    })
});

Abstraktion der $http Aufruf so , können Sie diesen Code auf mehreren Controllern wiederverwenden. Dies ist erforderlich, wenn der Code, der mit diesen Daten interagiert, komplexer wird. Möglicherweise möchten Sie die Daten verarbeiten, bevor Sie sie in Ihrem Controller verwenden, und das Ergebnis dieses Prozesses zwischenspeichern, damit Sie keine Zeit für die erneute Verarbeitung aufwenden müssen.

Sie sollten sich den "Dienst" als Darstellung (oder Modell) von Daten vorstellen, die Ihre Anwendung verwenden kann.


9

Die akzeptierte Antwort gab mir den $http is not definedFehler, also musste ich dies tun:

var policyService = angular.module("PolicyService", []);
policyService.service('PolicyService', ['$http', function ($http) {
    return {
        foo: "bar",
        bar: function (params) {
            return $http.get('../Home/Policy_Read', {
                params: params
            });
        }
    };
}]);

Der Hauptunterschied ist diese Linie:

policyService.service('PolicyService', ['$http', function ($http) {

1

Ich habe eine Antwort für jemanden gegeben, der einen völlig generischen Webdienst in Angular haben möchte. Ich würde empfehlen, es einfach anzuschließen, und es kümmert sich um alle Ihre Web-Service-Anrufe, ohne dass Sie alle selbst codieren müssen. Die Antwort ist hier:

https://stackoverflow.com/a/38958644/5349719

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.