dman
dman

Reputation: 11064

Angular.js $watch() not catching update from JS object member from Service

$watch() is not catching return sseHandler.result.cpuResult.timestamp after the first iteration. I'm not sure why, because I verified the datestamps are changing. Also, after the first iteration....if I click on the view repeatedly, the scope variables and view update with the new information...so it's like $watch does work...but only if I click on the view manually to make it work.

'use strict';

angular.module('monitorApp')
.controller('homeCtrl', function($scope, $location, $document) {
    console.log("s");
});

angular.module('monitorApp')
.controller('cpuCtrl',   ['$scope', 'sseHandler', function($scope, sseHandler) {
    $scope.sseHandler = sseHandler;
    $scope.avaiable = "";
    $scope.apiTimeStamp = sseHandler.result.cpuResult.timestamp;
    $scope.infoReceived = "";
    $scope.last15 = "";
    $scope.last5 = "";
    $scope.lastMinute = "";

    var cpuUpdate = function (result) {
        $scope.available = result.cpuResult.avaiable;
        $scope.apiTimeStamp = result.cpuResult.timestamp;
        $scope.infoReceived = new Date();
        $scope.last15 = result.cpuResult.metrics['15m'].data
        $scope.last5 = result.cpuResult.metrics['5m'].data
        $scope.lastMinute = result.cpuResult.metrics['1m'].data
    }
    $scope.$watch(function () {
        console.log("being caught");
        return sseHandler.result.cpuResult.timestamp},
     function(){
            console.log("sss");
            cpuUpdate(sseHandler.result);
    });
}]);


angular.module('monitorApp')
.controller('filesystemsCtrl', function($scope, $location, $document) {
    console.log("s");
});

angular.module('monitorApp')
.controller('httpPortCtrl', function($scope, $location, $document) {
    console.log("s");
});

angular.module('monitorApp')
.factory('sseHandler', function ($timeout) {
    var source = new EventSource('/subscribe');
    var sseHandler = {};
    sseHandler.result =  { "cpuResult" : { timestamp : '1'}  };
    source.addEventListener('message', function(e) {
         result = JSON.parse(e.data);
         event = Object.keys(result)[0];
         switch(event) {
             case "cpuResult":
                 sseHandler.result = result;
                 console.log(sseHandler.result.cpuResult.timestamp);
             break;
         }
    });
    return sseHandler;
});

Upvotes: 0

Views: 65

Answers (2)

gkalpak
gkalpak

Reputation: 48212

The changes in sseHandler.result.cpuResult.timestamp happen otuside of the Angular context (in the asynchronously executed event-listener callback), so Angular does not know about the changes.

You need to manually trigger a $digest loop, by calling $rootScope.$apply():

.factory('sseHandler', function ($rootScope, $timeout) {
    ...
    source.addEventListener('message', function (e) {
        $rootScope.$apply(function () {
            // Put all code in here, so Angular can also handle exceptions
            // as if they happened inside the Angular context.
            ...
        });
    }
    ...

The reason your random clicking around the app made it work, is because you probably triggered some other action (e.g. changed a model, triggered and ngClick event etc) which in turn triggered a $digest cycle.

Upvotes: 1

Nikolas
Nikolas

Reputation: 1176

Your message event in the EventListener does not start a new digest cycle. In your sseHandler try:

$timeout(function () {sseHandler.result = result;});

Upvotes: 1

Related Questions