AngularJS Factory mit asynchroner Aktualisierung

Gespeichert von Erik Wegner am/um Fr, 09.10.2015 - 14:19
Body

In AngularJS helfen Factories, den Code im Controller schlank zu halten und auf die wesentlichen Punkte zu reduzieren: Verknüpfen einer Datenquelle mit der Anzeige und Übergabe von Ereignissen an die richtigen Ziele.

Eine Factory ist ein Weg, die Datenbeschaffung zu delegieren. Wenn sich die Daten asynchron ändern, soll die Anzeige ebenfalls aktualisiert werden.

Dieser Tipp zeigt, wie asynchrone Datenänderungen direkt wirken.

Die fertige Lösung kann in diesem JSFiddle angesehen werden.

Das notwendige HTML-Gerüst beinhaltet den Rahmen für ng-app und einen Controller, dessen Daten als Liste ausgegeben werden.

<div ng-app="myApp">
    <div ng-controller="AbcCtrl">Seconds
        <ul>
            <li ng-repeat="s in seconds">{{s}}</li>
        </ul>
    </div>
</div>

Es wird AngularJS 1.4 verwendet.

Der dazugehörige JavaScript-Code initialisiert zuerst die Angular-Umgebung.

var frontpageApp = angular.module("myApp", []);

In der App wird nun eine Factory angemeldet, die später die Daten liefern kann. Die Factory ist abhängig von $rootScope. Das zurückgelieferte Objekt enthält ein Array items, dessen asynchrone Änderungen sollen in der Anzeige automatisch umgesetzt werden.

frontpageApp.factory(
    'DataProvider', ['$rootScope',
        function($rootScope) {
            var k = {}
            k.items = []

            k.startTimer = function() {/* ... */}

            /* ... */

            return k
        }
    ]);

Dafür wird nun der oben angemeldete DataProvider als Abhängigkeit angegeben. Die Instanz landet in der Variable $dp.

frontpageApp.controller(
    "AbcCtrl", ['$scope', 'DataProvider',

        function($scope, $dp) {
            $scope.seconds = $dp.items;
            $dp.startTimer();
        }
    ]);

Die Verwendung der Interval-Funktion im DataProvider simuliert die asynchrone Ausführung. Bei jedem Intervalldurchlauf ändert sich die Belegung der items. Damit nun die Anzeige ohne weitere Ereignis-Behandlung auf Änderungen reagiert, wird der $rootScope.$apply-Aufruf verwendet:

    k.startTimer = function () {
        if (timerhandle > 0) return;
        timerhandle = window.setInterval(tick, 1000);
    }

    tick = function () {
        var sec = (new Date).getSeconds() % 10;
        while (k.items.length > sec + 1) k.items.pop();
        while (k.items.length < sec + 1) {
            k.items.push(k.items.length.toString());
        }

        $rootScope.$apply();
    }

Damit ist die Aufgabe erfüllt.

Der Vollständigkeit halber hier der komplette JavaScript-Code:

var frontpageApp = angular.module("myApp", []);

frontpageApp.factory(
    'DataProvider', ['$rootScope',
        function($rootScope) {
            var k = {}
            k.items = []

            timerhandle = 0

            k.startTimer = function() {
                if (timerhandle > 0) return;
                timerhandle = window.setInterval(tick, 1000);
            }

            tick = function() {
                var sec = (new Date).getSeconds() % 10;
                while (k.items.length > sec + 1) k.items.pop();
                while (k.items.length < sec + 1) {
                    k.items.push(k.items.length.toString());
                }

                $rootScope.$apply();
            }


            return k
        }
    ]);

frontpageApp.controller(
    "AbcCtrl", ['$scope', 'DataProvider',

        function($scope, $dp) {
            $scope.seconds = $dp.items;
            $dp.startTimer();
        }
    ]);