DRobertE
DRobertE

Reputation: 3508

Service/Controller interaction with a $watch defined on a service property. The watch doesn't fire, can anyone clarify

I created a service which basically creates an interval, which will eventually do a $http post to a webapi to retrieve messages. Right now I'm just adding a new message object to an array for testing.

On the controller side I initialize the service and place a watch on one of the service properties, idea being when the service adds a new message I'll watch to display the notification to the user. Obviously this won't add a new message to the displayedNotifications array on EVERY call, but again this is just testing a prototyping.

The following is my service.

(function () {
    'use strict';

    var serviceId = "notificationService";

    //angular.module('app').factory(serviceId, ['helpersService', '$interval', function (helpersService, $interval) {
    angular.module('app').factory(serviceId, ['helpersService', '$interval', function (helpersService, $interval) {
        var defaultOptions = {
            url: undefined,
            interval: 1000
        };

        var myIntervalPromise = undefined;
        var displayedNotifications = [];

        //function onNotificationSuccess(response) {
        //    alert("in success");
        //    return response.data;
        //}

        //function onNotificationFailed(response) {
        //    alert("in Failure");
        //    throw response.data || 'An error occurred while attempting to process request';
        //}


        function initializeNotificationService(configOptions) {

            var passedOptions = $.extend({}, defaultOptions, configOptions);

            if (passedOptions.url) {

                myIntervalPromise = $interval(
                    function() {
                        console.log(passedOptions.url);
                        // eventually this push will accept a string/object returned from a webapi call
                        displayedNotifications.push({ messageobject: "this is new message" });
                    }, passedOptions.interval);

                //alert("in initializeNotificationService");
                return myIntervalPromise;
            }
            return myIntervalPromise;
        }

        //$scope.$on('$destroy', function() {
        //    if (angular.isDefined(myIntervalPromise)) {
        //        $interval.cancel(myIntervalPromise);
        //        myIntervalPromise = undefined;
        //    }
        //});

        return {
            // methods
            initializeNotificationService: initializeNotificationService,
            //properties
            displayedNotifications : displayedNotifications
        };
    }]);

})();

The following is my controller

(function () {
'use strict';

var controllerId = 'MessageCtrl';

angular.module('app').controller(controllerId, ['notificationService', '$scope', 

function (notificationService, $scope) {
        var vm = this;
        //vm.notifications = [];

        vm.initialize = function () {
            // initialize tyhe notification service here
            notificationService.initializeNotificationService({url:'this is a test url', interval: 5000})
                .then(
                    function (response) {
                        vm.notifications.push(response);
                         alert("successful call");
                    },
                    function(response) {
                         alert("failure to call");
                    },
                    function(iteration) {
                        // **a break point here clearly shows this property being changed**
                        console.log(notificationService.displayedNotifications);
                        //NEW EDIT HERE
                        $scope.notifications = notificationService.displayedNotifications;
                    }
                );

            $scope.$watch('notifications ', function (newValues, oldValues) {
                alert("watcher notified that notifications have changed");
            }, true);
        };

        vm.alertClicked = function (alert) {
            alert.status = 'old';
        };

        // call to init the notification service here so when the controller is loaded the service is initialized
        vm.initialize();

    }]);
})();

I would expect that every 5 seconds when a new message object is added to the services displayedNotifications property that the alert in the watch function would fire. However it only fires ones when everything is initialized then it doesn't again. What am I doing wrong?

NEW EDIT

Changed the notifcation function of the '.then' in the controller to assign the value of displayNotifications to set $scope.notifications and set the watch to that variable and that worked. But that being said it seems bad to set a variable at the $scope level... is there a way to watch a variable on the controller such as the commented out line of vm.notifications =[]; ???

Upvotes: 0

Views: 137

Answers (1)

a better oliver
a better oliver

Reputation: 26828

notificationService.displayedNotifications is not on the scope. You call **$scope**.$watch after all.

You can add either the service or just the property to the scope:

$scope.displayedNotifications = notificationService.displayedNotifications;
$scope.watch('displayedNotifications', ...

In your case there is no notificationService.displayedNotifications on the scope, so it can't change. That's why the function runs only once.

Another alternative is using a function as watch expression:

$scope.$watch(function() {
    return notificationService.displayedNotifications.length;
  }, function (newValues, oldValues) {

Angular checks if the return value of the function has changed.

As @ShawnC. mentioned you can also use events. In your service you send one via $rootScope.$broadcast and in your controller you receive it with $scope.$on (I wouldn't use $rootScope in the controller).

The last alternative I can think of is handle it in your callbacks. They are called anyway so a watch is kind of an overhead.

Upvotes: 1

Related Questions