Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Receiving broadcasts and calling controller functions from isolated scope/directive in AngularJS?

Here is the jsfiddle exemplifying my situation.

First of all, is this the correct way to create directives with the received dimensions? Then, each directive should be isolated from the others.. hence I am using scope: {}.

The problem is calling functions that are in the controller.. and it seems it does not receive the broadcast either..

I am sure this is a trivial problem.. I am new to Angular :)

I have a page in which I load a number of components with ng-repeat:

<div ng-app="test">
    <div ng-controller="containerCtrl">
        <component ng-repeat='c in components' id="c.id" my-width="{{c.width}}" my-height="{{c.height}}">
    </div>
</div>

The controller:

controller('containerCtrl', function ($scope) {
    $scope.components = [{ id: "c1", width: 100, height: 100 },
                        { id: "c2", width: 200, height: 100 },
                        { id: "c3", width: 300, height: 100 }];

    //in the actual controller I am using a socket provider and doing
    //socket.forward([
    //        'initPage',
    //        'refreshPage'
    //    ], $scope);
    //simulating it with a simple broadcast here..
    $scope.$broadcast("onSomething", "");

    $scope.doSomething = function (data) {
        alert("doing something");
    };
}).

and the directive:

directive('component', function () {
        var linkFn = function(scope, element, attrs) {
            $(element).
                resizable({
                    stop: function( event, ui ) {
                        scope.emitSomething(attrs.id, ui.position);
                    }
                });

            scope.$on('onSomething', function(res) {
                alert("onSomething!");
            });
        };

        return {
            restrict: 'E',
            template: '<div class="ui-widget-content" style="width: {{width}}px; height: {{height}}px;"></div>',
            replace: true,
            scope: {
                width:'@myWidth',
                height:'@myHeight'
            },
            link : linkFn
        };
    });
like image 619
fusio Avatar asked Aug 02 '13 13:08

fusio


1 Answers

The controller executes before the link function, so your broadcast is being sent out too soon. You can delay this using $timeout:

$timeout(function() {
    $scope.$broadcast("onSomething", "");
});

To call a controller method from a directive with an isolate scope, you need to specify the method as an argument:

<component ng-repeat='c in components' id="c.id" my-width="{{c.width}}" 
 my-height="{{c.height}}" callbk="doSomething(data)">

and you need to use the & syntax in the directive:

scope: {
    width: '@myWidth',
    height: '@myHeight',
    emitSomething: '&callbk'
},

To pass parameters to that callback/controller function, you need to use the proper syntax: scope.localDirectiveName({arg1: ..., arg2: ...}). In the fiddle, I only used one argument, and passed the two parameters in an array instead:

$(element).resizable({
   stop: function (event, ui) {
      scope.emitSomething({data: ["id", "position"]});
   }
});

fiddle

like image 92
Mark Rajcok Avatar answered Sep 28 '22 16:09

Mark Rajcok