Warm tip: This article is reproduced from stackoverflow.com, please click
angularjs angularjs-scope callback model-binding stompjs

AngularJS Why is this controller variable not getting updated in the UI?

发布于 2020-04-08 09:29:10

I'm having a controller using StompJS to subscribe to a url (back-end is Spring Java) that returns an alternating string "list" and "box" every 5 seconds. I want to update my UI element when StompJS receives some data, but I couldn't get the UI element to update. I've test the same logic with a $timeout and the UI is getting updated so it must has something to do with the way callback function works. Can anyone see what is the reason UI is not updating?

I have these simple UI elements:

<input ng-model="ctrl.uniqueId"/>
<input ng-model="test"/>

ctrl.uniqueId is to verify whether the actual controller instance is being updated. For some reason, only 1 controller is making 5 different subscribes every time. If someone can help with that, it'd be great too but I doubt you can get much info unless you see all my codes setup.

Anyway, in my controller (tried self.test and it didn't work so I tried with $scope.test to see if it makes a difference):

self.uniqueId = window.performance.now();
$scope.test = 'list';

// the UI will be updated to dummy after 3 seconds.
$timeout(function() {
    $scope.test="dummy";
}, 3000);

// the UI will not update.
var callBackFn = function(progress) {
    $scope.test = progress;
    console.log(self.uniqueId + ": " + $scope.test);
};

// the server returns alternating data (list and box) every 5 seconds
MyService.subscribeForUpdate('/topic/progressResults', callBackFn);

This is my service's code for StompJS if that matters:

self.subscribeForUpdate = function(channelUrl, callBackFn) {
    self.socket.stomp.connect({}, function() {
        self.socket.subscription = self.socket.stomp.subscribe(channelUrl, 
            function (result) {
                //return angular.fromJson(result.body);
                callBackFn(result.body);
                return result.body;
            }
        );
    });
};

This is console.log results:

1831.255000026431: list
1831.255000026431: box

Extra: is it possible to get the return data without callback function similar to Promise?

Questioner
user3758745
Viewed
58
georgeawg 2020-02-02 01:31

Be sure to use $apply:

app.service("myService", function($rootScope) {
    var self = this;
    self.subscribeForUpdate = function(channelUrl, callBackFn) {
        self.socket.stomp.connect({}, function() {
            self.socket.subscription = self.socket.stomp.subscribe(channelUrl, 
                function (result) {
                    //return angular.fromJson(result.body);
                    $rootScope.$apply(function() {
                        callBackFn(result.body);
                    });
                    return result.body;
                }
            );
        });
    };
})

AngularJS modifies the normal JavaScript flow by providing its own event processing loop. This splits the JavaScript into classical and AngularJS execution context. Only operations which are applied in the AngularJS execution context will benefit from AngularJS data-binding, exception handling, property watching, etc... You can also use $apply() to enter the AngularJS execution context from JavaScript.

Keep in mind that in most places (controllers, services) $apply has already been called for you by the directive which is handling the event. An explicit call to $apply is needed only when implementing custom event callbacks, or when working with third-party library callbacks.

For more information, see