简体   繁体   中英

$apply from factory in angularjs

I am fetching data from websocket in a factory. Every time a message arrives I update it.

In my controller I have bound the same inside the $scope. However when the websocket message comes, UI doesn't get updated.

After doing a lot of search I figured out that I need to call $scope.$apply if I need to update the UI (if changes are not saved by using any angular method).

I set up a timer using setInterval to call $scope.$apply every second. But it is a hack. I would like to remove this. Is there a way to tell angular to refresh from inside the factory, without using this hack?

Factory:

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;
});

Controller:

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);
});

You can not use $scope in an AngularJS service, since services do not belong to any scope, but they are singlenton through the application.

But you CAN inject the $rootScope into the service and notify through the entire application, like this:

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;
});

Notice that:

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

Add $rootScope in your factory and broadcast a message when the stockmarket has change.

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;
}])

Then in your controller just listen for that broadcast message and update your $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
    }
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM