WebSocket Service update Scope in Angular (Using n

2020-06-22 00:20发布

I'm trying to get data coming from a websocket to automatically update value inside a controller's scope.

My Service:

mimosaApp.service("Device", function ($websocket) {
    var self = this;
    var ws = $websocket.$new({
        url: "ws://" + window.location.host + ":81",
        //mock: true,
        reconnect: true
    });
    this.data = {};

    ws.$on("$open", function() {
        ws.$emit("get", "device");
    });
    ws.$on("$message", function (message) {
        console.log("WS Received", message);
        for(var key in message) {
            self.data[key] = message[key];
        }
        console.log(self.data); // At this point, self.data contains the proper data.
    });
    this.send = function (obj) {
        ws.$emit("set", obj);
    };
});

And my simple controller:

angular.module("MimosaApp").controller("PageController", ["Device", "$scope", "$http", function(Device, $scope, $http) {
    $scope.device = Device;
}]);

When a socket connection is made, the browser sends a message asking for data (the $open event). When it gets a response, it updates the Device.data object with the JSON object.

But I'm not seeing this reflect inside my controller scope/view. If inside the Controller, I set something like Device.data.name ='blah'; I can see the name property in the controller scope/view.

I'm a little new to Angular so sorry if my question doesn't quite make sense. :)

My view is trying to use it like:

<div class="container-fluid">
    location
    <ul>
        <li ng-repeat="(key, value) in device.data">
            {{key}}: {{ value }}
        </li>
    </ul>
    <p>{{device.data.face}}</p>
</div>

2条回答
狗以群分
2楼-- · 2020-06-22 00:50

Looking at the source it does not seem to invoke digest cycle using scope.$apply within the $on handler. Which means that angular does not know about any update to its view bindings, so no change gets reflected in the view. So you would need to do it manually in your service, you could either inject a $rootScope or just a $timeout to trigger a digest cycle.

Example:-

inject $timeout

 ws.$on("$message", function (message) {
        console.log("WS Received", message);
        for(var key in message) {
            self.data[key] = message[key];
        }
        console.log(self.data); // At this point, self.data contains the proper data.
       $timeout(angular.noop); //<-- just invoke a dummy digest
    });

inject $rootScope

 ws.$on("$message", function (message) {
        console.log("WS Received", message);
        for(var key in message) {
            self.data[key] = message[key];
        }
        console.log(self.data); // At this point, self.data contains the proper data.
      $rootScope.$apply(); //invoke digest
    });

Or even create a dummy promise in your service using $q.

mimosaApp.service("Device", function ($websocket, $q) {
    var self = this;
    var _dummyPromise = $q.when(); //<-- here
    var ws = $websocket.$new({
        url: "ws://" + window.location.host + ":81",
        //mock: true,
        reconnect: true
    });
    //...


    ws.$on("$message", function (message) {
        console.log("WS Received", message);
        for(var key in message) {
            self.data[key] = message[key];
        }
       _dummyPromise.then(angular.noop); //<-- here
    });
    this.send = function (obj) {
        ws.$emit("set", obj);
    };
});
查看更多
啃猪蹄的小仙女
3楼-- · 2020-06-22 00:51

The most likely cause is that the $on callback isn't triggering a $digest cycle to inform the rest of the app of any change.

You can do that manually by injecting $rootScope

mimosaApp.service("Device", function ($rootScope, $websocket)

and then triggering a $digest after updating your data

ws.$on("$message", function (message) {
    console.log("WS Received", message);
    for(var key in message) {
        self.data[key] = message[key];
    }
    if(!$rootScope.$$phase) { // prevents triggering a $digest if there's already one in progress
        $rootScope.$digest()
    }
    console.log(self.data); // At this point, self.data contains the proper data.
});
查看更多
登录 后发表回答