Übergabe des aktuellen Bereichs an einen AngularJS-Dienst

106

Ist es richtig, den "Strom" $scopean einen AngularJS-Dienst weiterzuleiten ?

Ich bin in der Situation, dass ich einen $ -Dienst habe, der weiß, dass er nur von einem Controller verwendet wird, und ich möchte einen Verweis auf den Umfang des Controllers in den $ service-Methoden selbst haben.

Ist das philosophisch korrekt?

Oder sollte ich Ereignisse besser an $ rootScope senden und dann von meinem Controller abhören lassen?

SC
quelle
1
Können Sie uns vielleicht genauer mitteilen, was Sie versuchen zu tun? Vielleicht ist es überhaupt nicht notwendig, den Umfang auf den Dienst zu übertragen?
Ganaraj
Nun, es ist nicht so schwer. Ich möchte einfach auf die $scopeEigenschaften zugreifen und $scope.$applybei Bedarf anrufen können.
SC
Angenommen, ich möchte Änderungen, die vom $ service stammen, auf den $ scope anwenden. Hoffe es ist jetzt klarer.
SC
8
Ich schlage vor, dass Sie die $ scope-Eigenschaften, auf die Ihr Dienst zugreifen soll, in den Dienst selbst einfügen (anstatt sie im Controller zu haben). Services sind bessere Orte zum Speichern von Modellen / Daten als Controller.
Mark Rajcok
@ MarkRajcock Ich versuche auch dieses Problem zu verstehen. Momentan rufe ich nur einen Dienst an und hänge die bereitgestellten Daten an den Controller an $scope. Wie würde der Controller direkt auf die Daten im Dienst zugreifen und sie an die Ansicht übergeben, ohne dies zu tun?
drjimmie1976

Antworten:

67

Verwenden Sie Angular-Versprechen, um den Controller zu informieren, wenn etwas Asynchrones passiert .

Um das zu provozieren $apply, benötigen Sie den Bereich nicht, den Sie aufrufen können $rootScope.$apply, da es keinen Unterschied gibt, ihn in einem bestimmten Bereich oder im Stammverzeichnis aufzurufen.

In Bezug auf das Lesen der Variablen ist es besser, wenn Sie Parameter erhalten. Sie könnten es aber auch aus einem Bereich als Objektparameter lesen, aber ich würde mich für einen Parameter entscheiden, der Ihre Serviceschnittstelle viel klarer macht.

Caio Cunha
quelle
Ich denke, dies ist die Antwort, die meine Zweifel an AngularJS-Anfängern besser löst.
SC
@Caio Cunha Könnten Sie näher erläutern, warum es keine gute Idee ist, einen Bereich zu übergeben? Ich habe genau dieses Problem. Ich möchte einige Dinge $scopeüber einen Aufruf eines Dienstes mithilfe einer asynchronen executeSql()Funktion hinzufügen . Wenn Sie sich 3 Optionen ansehen (1), verwenden Sie einen Rückruf für die Async-Funktion und rufen Sie dann auf $scope.$apply... dies funktioniert, ist aber hässlich. (2) $scopeÜbergeben Sie die Funktion für die Async-Funktion. Rufen Sie dann auf. theScope.$apply()Dies funktioniert auch. (3) Verwenden Sie ein Versprechen. .. noch nicht versucht. Warum ist ein Versprechen der beste Weg? Vielen Dank!
drjimmie1976
15

Ich würde sagen, wenn Ihre Funktionalität nur für einen Controller spezifisch ist, benötigen Sie keinen Dienst.

Die Aufgabe des Controllers besteht darin, das spezifische Modell zu manipulieren, während ein Dienst globale Aufgaben behandeln sollte. Ich würde mich lieber an dieses Paradigma halten, anstatt die Dinge durcheinander zu bringen.

Das sagen die Dokumente

Bedienung

Winkeldienste sind Singletons, die bestimmte Aufgaben ausführen, die Web-Apps gemeinsam haben

Regler

In Angular ist ein Controller eine JavaScript-Funktion (Typ / Klasse), mit der Instanzen von Angular Scope mit Ausnahme des Root-Bereichs erweitert werden.

PS: Abgesehen davon können Sie, wenn Sie verdauen müssen, auch das $ rootScope in Ihren Dienst injizieren.

F Lekschas
quelle
2
Vielen Dank. Tolle Antwort. Wenn ich tief in meine Situation gehe, geht es darum, dass ich Service verwende, weil ich einen Singleton möchte. Es gibt nur einen Controller, der den Service nutzt, aber dieser Controller kann während des App-Lebenszyklus mehrmals instanziiert werden. Daher möchte ich, dass der Service immer im selben Status ist.
SC
Auf jeden Fall ist die Klarstellung über den Aufruf $applyoder $digestdas $ rootScope für mich völlig sinnvoll.
SC
1
Ich würde es immer noch in einem Service zum Testen getrennt halten.
Bluehallu
Wenn die Funktionalität für eine Instanz eines Controllers spezifisch ist, können Sie die Implementierung eines Dienstes überspringen, andernfalls jedoch nicht, da Sie die Möglichkeit opfern, den Status zwischen diesen Instanzen gemeinsam zu nutzen. Nur weil es heute nur einen einzigen Controllertyp gibt, heißt das nicht, dass es morgen keinen anderen Controller gibt, der die Funktionalität nutzen kann. Darüber hinaus kann ein Dienst ein Aufblähen des Controllers vermeiden. Es geht also nicht so sehr darum, ob es einen einzelnen Controller gibt, sondern darum, welche Funktionalität in Frage kommt.
Nick
9

Ja. Sie können den Bereich $ an den Service übergeben, wenn Sie ihn initialisieren. Im Servicekonstruktor können Sie den Bereich so etwas zuweisen._scope und dann auf den Bereich innerhalb des Service verweisen!

angular.module('blah').controller('BlahCtrl', function($scope, BlahService) {

    $scope.someVar = 4;

    $scope.blahService = new blahService($scope);

});

angular.module('blah').factory('blahService', function() {

    //constructor
    function blahService(scope) {
        this._scope = scope;

        this._someFunction()
    }

    //wherever you'd reference the scope
    blahService.prototype._someFunction = function() {

        this._scope['someVar'] = 5;

    }

    return blahService;

});
user12121234
quelle
1
+1 Ich würde jedoch gerne eine Möglichkeit sehen, die einzelnen Controller automatisch zu kennen, $scopewenn dieser Controller den Service injiziert, um keine Methode für den Service aufrufen und manuell $scopean ihn übergeben zu müssen.
Cody
2
@Cody Ich empfehle das nicht, da es im Widerspruch zu Dependency Injection
Coldstar
Einverstanden, +1 für das Abschießen! Wahrscheinlich auch Metzger DIP - ich würde sagen, auf die Gefahr hin, überflüssig zu werden.
Cody
Sie mischen hier Dienstleistungen mit Fabriken. Diese Lösung verwendet eine Fabrik, die sich von einem Service unterscheidet. Der Hauptunterschied besteht darin, dass ein Dienst ein (Singleton-) Objekt zurückgibt. Während eine Factory eine Funktion zurückgibt, die instanziiert werden kann ( new MyFunction()). Die Frage betraf einen Dienst, bei dem ein Anruf newnicht möglich ist.
Karvapallo
@ Karvapallo Guter Punkt. Als Kontrapunkt glaube ich, dass sich Winkeldienste auf eine Fabrik, einen Dienst und einen Anbieter (ng-wat) beziehen.
user12121234
6

Ich persönlich halte die Weitergabe $scopean einen Dienst für eine schlechte Idee , da dadurch ein Zirkelverweis entsteht: Der Controller hängt vom Service ab, und der Service hängt vom Umfang des Controllers ab.

Abgesehen davon, dass sie in Bezug auf die Beziehungen verwirrend sind, stehen solche Dinge dem Müllsammler im Weg.

Mein bevorzugter Ansatz besteht darin, ein Domänenobjekt in den Controller-Bereich zu stellen und dieses an den Dienst zu übergeben. Auf diese Weise funktioniert der Dienst unabhängig davon, ob er in Zukunft in einem Controller oder in einem anderen Dienst verwendet wird.

Wenn der Dienst beispielsweise Elemente aus einem Array pushen und entfernen soll, lautet errorsmein Code:

var errors = [];
$scope.errors = errors;
$scope.myService = new MyService(errors);

Der Dienst interagiert dann mit der Steuerung, indem er weiterarbeitet errors. Natürlich muss ich vorsichtig sein, niemals die gesamte Array-Referenz auszulöschen, aber am Ende des Tages ist das ein allgemeines JS-Problem.

Ich würde niemals Rundfunk $applyund / oder ähnliche Dinge verwenden wollen, weil imho gute OO-Praktiken immer die Angular-Magie übertreffen werden.

Marco Faustinelli
quelle
1
Hat dieser Code einen Unterschied zu diesem?:$scope.errors = []; $scope.myService = new MyService($scope.errors);
Soldeplata Saketos
@ SoldeplataSaketos - Ja, das tut es. errorslebt unabhängig von $scope. Das ist der springende Punkt dieser Antwort. Bitte überprüfen Sie den Link, den ich im Text angegeben habe. Prost.
Marco Faustinelli
1
Wenn ich Ihren Code richtig verstehe, $scope.errorszeigt er auf var errorsund die variablen Fehler erscheinen mir überflüssig, da es sich nur um einen weiteren Zeiger handelt. Eine ähnliche Situation, die ich mir vorstellen kann und die offensichtlich überflüssig ist, ist dieser Code : const errors = errors2 = errors3 = []; $scope.errors = errors;. Stimmen Sie zu, dass nur der von Ihnen bereitgestellte Code var errors = []überflüssig erscheint?
Soldeplata Saketos
Nein, ist es nicht. Ich wiederhole mich Wort für Wort: errorslebt unabhängig von $scope. Sie müssen verstehen, was ein Domänenobjekt ist und was eine varZuweisung ist. Wenn der von mir bereitgestellte Link nicht ausreicht, steht ausreichend anderes Material zur Verfügung.
Marco Faustinelli
Nun, das hängt ausschließlich von der Implementierung der Funktion ab MyService(errors). Nach meinem Verständnis sollte der Dienst ein Protokollierungsarray basierend auf dem Parameter (in diesem Fall einem Zeiger) generieren. Für mich ist das ein schlechtes Muster, da die Dienste Singletons im Winkel sind. Wenn die Implementierung des Dienstes gut programmiert ist, sollte das Array in einer internen Variablen generiert werden (um weiterhin ein Singleton zu sein). Daher ist es nicht sinnvoll, die Variable außerhalb des Dienstes zu initialisieren.
Soldeplata Saketos