jiaming
jiaming

Reputation: 683

angularJS $broadcast and $on

is there a way to make the $broadcast propagate the variable to the $on during initialization phase?

<div ng-app='test'>
    <div ng-controller='testCtrl'> <span>{{testContent}}</span> 
    </div>
    <div ng-controller="testCtrl2">
        <input type='text' ng-change="updateContent()" ng-model="testContent2" />
    </div>
</div>

 

var app = angular.module('test', []);
app.factory('sharedContent', function ($rootScope) {
    var standardContent;
    var resizeProportion;
    return {
        setStandardContent: function (newStandardContent) {
            standardContent = newStandardContent;
            $rootScope.$broadcast('updateContent');
            console.log('broadcast');
        },
        getStandardContent: function () {
            return standardContent;
        },
        setResizeProportion: function (newResizeProportion) {
            $rootScope.$broadcast('updateResizeProportion');
        },
    }
});
app.run(function (sharedContent) {
    sharedContent.setStandardContent('haha');
});

function testCtrl($scope, sharedContent) {
    $scope.testContent;
    $scope.$on('updateContent', function () {
        console.log('receive');
        $scope.testContent = sharedContent.getStandardContent();
    });
}

function testCtrl2($scope, sharedContent) {
    $scope.testContent2 = 'test';
    $scope.updateContent = function () {
        sharedContent.setStandardContent($scope.testContent2);
    };
}

Sample fiddle : http://jsfiddle.net/jiaming/NsVPe/

The span will display the value as the input changes, which is due to the ng-change function.

However, at initialization phase, the value "haha" was not propagated to the $scope.testContent and thus, nothing was shown at first runtime. Is there a way to make the value "haha" appear at the first runtime?

Thank you.

Upvotes: 8

Views: 10056

Answers (3)

Ankur Rathi
Ankur Rathi

Reputation: 109

Just provide a little delay using $timeout function. Just update the code in the factory it will start working.

Please refer the code below for the factory:

app.factory('sharedContent', function ($rootScope,$timeout) {
    var standardContent;
    var resizeProportion;
    return {
        setStandardContent: function (newStandardContent) {
            standardContent = newStandardContent;
            $timeout(function(){
              $rootScope.$broadcast('updateContent');
            },0)
             console.log('broadcast');
        },
        getStandardContent: function () {
            return standardContent;
        },
        setResizeProportion: function (newResizeProportion) {
            $rootScope.$broadcast('updateResizeProportion');
        },
    }
});

Upvotes: 1

Gonzalo Ruiz de Villa
Gonzalo Ruiz de Villa

Reputation: 341

The thing that you are not taking into account that the run phase of the app gets executed before the controllers are initialized. Because broadcasted messages don't get buffered and are only served to the listeners that are listening in the moment the message is created, the haha value gets lost.

In your case, however, it's quite easy to make it work with a small change in your controller:

function testCtrl($scope, sharedContent) {
  updateTestContent();
  $scope.$on('updateContent', updateTestContent);

  function updateTestContent(){
     $scope.testContent = sharedContent.getStandardContent();
  }
}

I forked your JSFiddle here http://jsfiddle.net/y3w5r01d/2/ where you can see on the console when each function (run and controllers) gets executed.

Upvotes: 0

callmekatootie
callmekatootie

Reputation: 11228

The reason for this is that the ng-change triggers upon subsequent changes to the model identified by testContent2. When the controller initializes, the value "test" is assigned to it. ng-change then keeps a track of subsequent changes - the initial assignment does not qualify for this, only subsequent changes do.

http://jsfiddle.net/vZwy4/ - I updated the fiddle provided by you. Here you can see that the span tag is correctly populated with the data.

What you needed to do was instead of using ng-change, you should use the scope's $watch functionality. So remove the ng-change directive from the input box and remove the updateContent method. Instead, replace it with the following code wherein you watch the changes to the testContent2 model:

$scope.$watch('testContent2', function () {
    if ($scope.testContent2 === undefined || $scope.testContent2 === null) {
        return;
    }

    sharedContent.setStandardContent($scope.testContent2);

});

You can now see that the word "test" (I could not find anything to do with 'haha') appears the moment the page loads. Subsequent changes to the input are also updated in the span. Hope this is what you were looking for.

Upvotes: 0

Related Questions