Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

$watch a service variable or $broadcast an event with AngularJS

I'm using a service to share data between controllers. The application has to update the DOM when a variable is modified. I've found two ways to do that, you can see the code here:

http://jsfiddle.net/sosegon/9x4N3/7/

myApp.controller( "ctrl1", [ "$scope", "myService", function( $scope, myService ){
    $scope.init = function(){
        $scope.myVariable = myService.myVariable;
    };
}]);

myApp.controller( "ctrl2", [ "$scope", "myService", function( $scope, myService ){
    $scope.increaseVal = function(){
        var a = myService.myVariable.value;
        myService.myVariable.value = a + 1;
    };
}]);

http://jsfiddle.net/sosegon/Y93Wn/3/

myApp.controller( "ctrl1", [ "$scope", "myService", function( $scope, myService ){
    $scope.init = function(){
        $scope.increasedCounter = 1;
        $scope.myVariable = myService.myVariable;
    };
    $scope.$on( "increased", function(){
        $scope.increasedCounter += 1;
    }
}]);

myApp.controller( "ctrl2", [ "$scope", "myService", function( $scope, myService ){
    $scope.increaseVal = function(){
        myService.increaseVal();
    };
}]);

In the first case, I share a variable from the service with the controller and $watch it in the directive. Here, I can modify the variable directly in this controller, or any other controller that share it, and the DOM is updated.

In the other option, I use a function from the service to modify the variable which $broadcast an event. That event is listened by the controller, then the DOM is updated.

I'd like to know which option is better and the reasons for that.

Thanks.

EDIT:

The code in jsFiddle, is a simplified version of the real code which has more objects and functions. In the service, the value field of myVariable is actually an object with much more information than just a primitive type; that information has to be displayed and updated in the DOM. The object myVariable.value is set in every change:

myVariable.value = newValue;

When that happens all the DOM elements have to be updated. Since the information contained in myVariable.value is variable, the number of properties changes (I can't use an array), it's much easier to delete the DOM elements and create new ones, that's what I'm doing in the directive (but with more elements in the real code):

scope.$watch( "myVariable.value", function( newVal, oldVal ){

            if( newVal === oldVal ){

                return;

            }

            while( element[0].children.length > 0 ){

                element[0].removeChild( element[0].firstChild );

            }


            var e = angular.element( element );
            e.append( "<span>Value is: " + scope.myVariable.value + "</span>" );

        } );
like image 876
sosegon Avatar asked Aug 24 '13 00:08

sosegon


1 Answers

Your code is over complex. I am not sure what are you trying to do with that directive.

You don't have to $watch nor $broadcast anything.

You have a object in your service which has a primitive. In ctrl1 you're assigning the object to the $scope (That is good, because if we assign it to the primitive, it will need a $watch for sure as seen here.

So far so good. To increase the value, there is an easy way just doing myVal++ no need of temporary variables.

For the directive, I am not sure what's your goal here, I simplified it to what you need to put that example to work. You don't need to $watch nor $broadcast. ctrl1 is aware of the changes made to myVariable object so if it changes, you will notice it.

Code:

var myApp = angular.module( "myApp", [] );

myApp.provider( "myService", function(){

    var myVariable = {
        value: 0
    };
    this.$get = function(){
        return {
            myVariable: myVariable,
            increase: function() {
                myVariable.value++;
            }
        };
    };
});

myApp.directive( "dir1", function(){
    return {
        restrict: 'EA',
        template: '<div>value: {{myVariable.value}}</div>',
        replace: true
    };
});


myApp.controller("ctrl1", ["$scope", "myService", function($scope, myService){
    $scope.myVariable = myService.myVariable;
}]);

myApp.controller( "ctrl2", [ "$scope", "myService", function( $scope, myService ){
    $scope.increaseVal = myService.increase;
}]);

View:

<body ng-app = "myApp">
    <div dir1="myVariable.value" ng-controller = "ctrl1">
    </div>

    <div ng-controller = "ctrl2">
        <button ng-click = "increaseVal()">
            Increase
        </button>
    </div>


</body>

Here is my forked fiddle: http://jsfiddle.net/uWdUJ/ Same idea a little bit cleaned.

like image 148
Jesus Rodriguez Avatar answered Oct 04 '22 21:10

Jesus Rodriguez