it-swarm.com.de

AngularJS mit $ rootScope als Datenspeicher

Ich habe eine Idee für meine AngularJS-App und bin gespannt, ob die AngularJS-Community dies für in Ordnung hält ...

Kurz gesagt, ich stelle eine Verbindung zu einer Daten-API her und zeige meine Ergebnisse auf der Seite an. Ich habe einen angular Dienst erstellt, der einen Datenspeicher auf $ rootScope.DataStore erstellt. Ich habe auch eine Dienstmethode, die den DataStore mit den von einem API-Endpunkt zurückgegebenen Daten aktualisiert. products "API-Endpunkt von meinem Controller aus mit DataStore.update ('products'), dies würde $ rootScope.DataStore.products mit meinen Produktdaten aktualisieren. Jetzt muss ich in der Ansicht/partiell nur noch ng-repeat sagen = "Produkt in DataStore.Produkte", um meine Daten anzuzeigen, und es spielt keine Rolle, in welchem ​​Controller-Bereich ich mich befinde. Daher ist mein DataStore im Wesentlichen meine einzige Quelle der Wahrheit.

Was ich von dieser Methode gewinne, ist eine leicht zu verfolgende Semantik und eine minimale Controller-Codierung. Jedes Mal, wenn der DataStore aktualisiert wird, wird auch alles, was an DataStore gebunden ist, aktualisiert.

Würde dies den Digest-Zyklus von $ rootScope überlasten, oder ist dies nur ein seltsamer Weg, dies zu tun? Oder ist es ein total geiler Weg? :) Alle Kommentare sind willkommen.

57
Chris Collins

Diese Frage wird in den hier zitierten AngularJS FAQ behandelt:

Gelegentlich gibt es Daten, die Sie für die gesamte App globalisieren möchten. Für diese können Sie $ rootScope injizieren und Werte wie für jeden anderen Bereich festlegen. Da die Gültigkeitsbereiche vom Root-Gültigkeitsbereich erben, sind diese Werte für die Ausdrücke verfügbar, die Direktiven wie ng-show beigefügt sind, genau wie für die Werte in Ihrem lokalen $ Gültigkeitsbereich.

Es scheint, als würde das Team dazu ermutigen, $rootScope Folgendermaßen zu verwenden:

Natürlich ist der globale Status zum Kotzen und Sie sollten $ rootScope sparsam verwenden, so wie Sie es (hoffentlich) mit globalen Variablen in jeder Sprache verwenden würden. Verwenden Sie ihn insbesondere nicht für Code, sondern nur für Daten. Wenn Sie versucht sind, eine Funktion in $ rootScope zu implementieren, ist es fast immer besser, sie in einen Dienst zu integrieren, der dort implementiert und einfacher getestet werden kann.

Erstellen Sie umgekehrt keinen Dienst, dessen einziger Lebenszweck darin besteht, Datenbits zu speichern und zurückzugeben.

Dies belastet den Zyklus $digest (Der eine grundlegende Dirty-Prüfung zum Testen auf Datenmutation implementiert) nicht zu sehr, und dies ist keine ungewöhnliche Vorgehensweise.

EDIT: Weitere Informationen zur Leistung finden Sie in dieser Antwort von Misko (AngularJS dev) hier auf SO: Wie funktioniert die Datenbindung in AngularJS?) ? Beachten Sie insbesondere den Abschnitt zur Leistung.

88
Dan

Verwenden Sie einfach die $ cacheFactory, um alle Beteiligten zu beruhigen. Dies ermöglicht, dass die Datenanforderungsdienste zustandslos und im Grunde genommen nur ein Getter und Setter sind. Ich gebe zu, dass es praktisch ist, die Daten im $ rootScope oder als Eigenschaft im Service zu speichern, aber ich fühle mich einfach falsch. Die Verwendung der $ cacheFactory ist ebenfalls recht einfach.

Erstellen Sie zuerst einen Cache-Service:

angular.module('CacheService', ['ng'])
    .factory('CacheService', function($cacheFactory) {
    return $cacheFactory('CacheService');
});

Fügen Sie die js-Datei in Ihre app.js ein und fügen Sie sie dann in Ihre App-Deklaration ein:

var MyApp = angular.module('MyApp', ['CacheService']);

Injizieren Sie es in den Dienst, verwenden Sie es wie folgt:

'use strict'

MyApp.factory('HackerNewsService', function(CacheService) {
    return {
        getNews: function(key) {
            var news = CacheService.get(key);

            if(news) {
                return news;
            }

            return null;
        },
        setNews: function(key, value) {
            CacheService.put(key, value);
        },
        clearNews: function(key) {
            CacheService.put(key, '');
        }
    };
});

Jetzt müssen Sie nur noch Ihren HackerNewsService in Ihren Controller einfügen und ihn verwenden, indem Sie die von uns dafür erstellten Methoden aufrufen. Beispielsweise:

HackerNewsService.setNews('myArticle', {headline: 'My Article', body: 'This is the body'});
$scope.article = HackerNewsService.getNews('myArticle');
32
Jordan Papaleo

Ich habe die Erfahrung gemacht, dass die Verwendung von $ rootScope zum Speichern des Teils meines Datenmodells, der allen ngViews in meiner App gemeinsam ist, der bequemste Weg ist.

<div>{{mymodel.property}}</div>

ist für mich lesbarer und kürzer als

<div>{{getPropertyModel()}}</div>

mit dem Javascript

app.factory('MyModel', function(){
    return {
        getModel: function() { ... },
        setModel: function(m) { ... },
    }
});

app.controller('ctrl', ['$scope', 'MyModel', function($scope, MyModel){
    $scope.getPropertModel = function() {
        return MyModel.getModel().property;
    };
}]);

Verwendet man einen Service oder eine Cachefactory, wird jeder Zugriff auf das Modell in der HTML-Vorlage zu einer Funktion, die weniger lesbar ist als der Zugriff auf eine Eigenschaft des rootScope. Die Verwendung von $ rootScope führt zu weniger Code und damit zu weniger Fehlern und weniger Tests.

Natürlich wird nur der gemeinsame Teil aller ngView in $ rootScope gespeichert. Der Rest des Modells wird im lokalen Bereich $ gespeichert.

Überwacht eine Funktion auch langsamer als Objekteigenschaften. Aus Performance-Gründen ist $ rootScope auch besser.

8
Ruben Decrop

Ich stehe gerade vor dem gleichen Problem, und es scheint mir, dass das Speichern des global verfügbaren 'Speicherorts' der richtige Ansatz ist, aber dass $ rootScope nicht der ideale Ort ist.

Ich habe dies gerade genauer untersucht. Anstatt Ihre Daten in $ rootScope zu speichern, können Sie auch einen "Dienst" zum Verwalten Ihrer Daten/separater Anliegen verwenden, wie hier beschrieben (insbesondere das letzte Codebeispiel): http : //joelhooks.com/blog/2013/04/24/modeling-data-and-state-in-your-angularjs-application/

Dann erstellen Sie im "Dienst" mit diesem Ansatz, ob Sie die Daten im Speicher, cacheFactory, localstorage (wie auf hier angespielt) und/oder in Ihrer DB speichern (zB über AJAX), hängt von den Anforderungen Ihrer App ab. Es bedeutet auch, dass Änderungen an der Art und Weise, wie Sie Ihre Daten speichern, bei Bedarf unabhängig vorgenommen werden können.

0
Matty J

Ich glaube, ich bin mir nicht sicher, warum Sie das rootScope verwenden müssen? Die Lebensdauer einer Dienstinstanz bezieht sich auch auf die gesamte Anwendung. Unabhängig davon, welches Datenschema bzw. welche Semantik Sie verwenden, könnte dies auch direkt im Dienst selbst gespeichert und von mehreren Controllern gemeinsam genutzt werden. Eine dieser Methoden übersteht die Aktualisierung jedoch nicht wie die Verwendung von lokalem Speicher.

Der Rest klingt wie ein fauler Ladevorgang. Wo der Dienst das einzige ist, das "weiß", ob die Daten von der Fernbedienung geladen wurden und sie zurückgeben, wenn sie bereits zwischengespeichert sind, und sie zwischenspeichern und zurückgeben, wenn dies nicht der Fall ist? Wenn ich diesen Teil richtig verstehe, ist es ein gutes Muster.

edit: Hier gehe ich ähnlich vor wie beim Lazy Loading, beachte aber, dass der Cache nur im Service selbst enthalten ist:

angular.module('HN_Reddit_Mashup.Services', [])
    .factory('HackerNews', function($http) {
        var HackerNewsCache = {};
        return {
            get: function(url) {
                return HackerNewsCache[url] ||
                    (HackerNewsCache[url] = $http.jsonp("http://api.thriftdb.com/api.hnsearch.com/items/_search?q=" + url +     "&callback=JSON_CALLBACK"));
            },                
        };
    })
0
Jason