$从 angularjs 的工厂申请

$apply from factory in angularjs

我正在工厂中从 websocket 获取数据。每次收到消息我都会更新它。

在我的控制器中,我在 $scope 中绑定了相同的内容。然而,当 websocket 消息到来时,UI 没有得到更新。

经过大量搜索后,我发现我需要调用 $scope.$apply 如果我需要更新 UI(如果使用任何 angular 方法未保存更改).

我使用 setInterval 设置了一个计时器,每秒调用 $scope.$apply。但这是一个黑客。我想删除它。有没有办法告诉 angular 从工厂内部刷新,而不使用这个 hack?

工厂:

app.factory('StocksFactory', function() {
    ...
    factory.stocksCurrentPrices = {};

    // Subscribe to the websocket for stock prices
    const stocksSocket = new WebSocket('ws://...');
    stocksSocket.onmessage = function(event) {
        // Adding to current prices
        factory.stocksCurrentPrices[..] = ...;
    };

    return factory;
});

控制器:

app.controller('StocksController', function($scope, StocksFactory) {

    $scope.stocks = StocksFactory.stocksCurrentPrices;

    // HACK This is used to force the digest every second as the changes in $scope.stocks
    // was not reflected in the UI
    setInterval(function() {
        $scope.$apply();
    }, 1000);
});

您可以在工厂中注入 $rootScope 并在其中使用 $broacast 来发出它已更改的信息。

您不能在 AngularJS 服务中使用 $scope,因为服务不属于任何范围,但它们在应用程序中是单例的。

但是您可以将 $rootScope 注入服务并通过整个应用程序进行通知,如下所示:

app.factory('StocksFactory', function($rootScope, $timeout) {
    ...
    factory.stocksCurrentPrices = {};

    // Subscribe to the websocket for stock prices
    const stocksSocket = new WebSocket('ws://...');
    stocksSocket.onmessage = function(event) {
        // Adding to current prices
        factory.stocksCurrentPrices[..] = ...;

        // notify of changes
        $timeout(function() {
            $rootScope.$apply();
        })
    };

    return factory;
});

注意:

  • 您需要将 $rootScope.$apply(); 包裹在 $timeout 中,以便 Prevent error $digest already in progress
  • 可以使用$rootScope.$broadcast

在你的工厂添加$rootScope并在股市有变化时广播消息。

app.factory('StocksFactory', ['$rootScope', function($rootScope) {
    var factory = {}
    factory.stocksCurrentPrices = {};

    const stocksSocket = new WebSocket('ws://...');
    stocksSocket.onmessage = function(event) {
        factory.stocksCurrentPrices[..] = ...;
        $rootScope.$broadcast('stocks-just-change')
    };

    return factory;
}])

然后在您的控制器中收听该广播消息并更新您的$scope.stocks

app.controller('StocksController', function($scope, StocksFactory) {
    $scope.stocks = StocksFactory.stocksCurrentPrices;

    $scope.$on('stocks-just-change', function(){
        $scope.stocks = StocksFactory.stocksCurrentPrices;
        //$scope.$apply() //use this if you'll receive updates very very fast
    }
})