简体   繁体   中英

Perform Default Action for each Function in a Directive

I've created some directives which have some functions, something like this:

myCtrl.directive('myDirective', function () {
    return {
        restrict: 'E',
        scope: {
            'something': '='
        },
        link: function (scope, el, attr) { 
             function func1(){
                 //some stuff
                 scope.$apply();
             }
             function func2(){
                 //some stuff
                 scope.$apply();
             }
             function func3(){
                 //some stuff
                 scope.$apply();
             }
             //...
        }
    }
});

I have to call scope.$apply() in all the functions to update the view. In addition I don't want to define them in the controller. I don't know if there is a trick to avoid this kind of pattern. It is working but I think it's not a good solution.

UPDATE

There are more than 10 directives which we've created for some shapes, eg rectangle, circle, square etc. In these functions, which I called $apply in them, some methods like drag and scale are implemented. So I need to call $apply to modify changes in model and consequently the view will be updated. I don't know how can I make them able to aware scope automatically unless I write about 100 functions in a controller! In addition, I'm using some 3rd party libraries like d3.js . Some event like clicked are bounded for calling these functions.

The real truth is that you need to call $scope.$apply() whenever you're changing something outside angular digest cycle. Angular detects the changes by dirty checking during the digest cycle.

$timeout is also doing $apply ($rootScope.$apply())

Check Angular source code .

What I can suggest is create helper function which will handle that. Example:

var ngAware = function (fnCallback) {
    return function () {
        var result = fnCallback.apply(this, arguments);    
        $scope.$apply();
        return result;
    };   
};   

// usage
function func1 () {
    // impl...
}
var ngFunc1 = ngAware(func1);
// or
var func2 = ngAware(function func2 () {
    // impl...
});

Sure you need apply() ?

apply() is used when integrating 3rd party libraries (such as jQuery). In most cases, if you are not hooking up 3rd party javascript libraries, you can avoid $apply() by using the build in binding mechanism

For instance, the following snippet will call func1 using a 3 seconds timeout callback. then, func1 will manipulate the scope variable something and the view will be updated without the need to trigger $apply()

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.value = 'Hello';
});


app.directive('myDirective', function ($timeout) {
    return {
        restrict: 'E',
        template:'<h1>{{something}}</h1>',
        scope: {
            'something': '='
        },
        link: function (scope, el, attr) { 
             function func1(){
                scope.something += ' ' + scope.something;
             }

             $timeout(func1, 3000);
        }
    }
});

html

<body ng-controller="MainCtrl">
   <my-directive something="value"></my-directive>
</body>

http://plnkr.co/edit/42VYs0W2BC5mjpaVWQg3?p=preview

  • perhaps if you explain more about your use case i could expand my answer to your specific needs

wraps the function within $scope.$apply()

check this :

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
    $scope.value = 'Hello';
});


app.directive('myDirective', function ($timeout) {
    return {
        restrict: 'E',
        template:'<h1>{{something}}</h1>',
        scope: {
            'something': '='
        },
        link: function (scope, el, attr) { 
            scope.$apply(function(){

                function func1(){
                    //some stuff
                }

                function func2(){
                    //some stuff
                }

                function func3(){
                    //some stuff
                }
            })
        }
    }
});

If you have common functionality in you directives (circle, square, etc) you should group it. By example, we could have a directive to drag

.directive('ngDraggable', [function () {

    return {
        link: function ($scope) {

            var stopHandler = function () {

                $scope.apply(function () {
                    // Code to handler the end of the dag event

                    // Notify the other directive.
                    $scope.$emit('dragStopped', data);
                });
            };

            // Initialization of the drag functionality.
        }
    }
}])

You can used as

<div ng-circle ng-draggable></div>

So, you earn three thing. First, the circle directive can do changes in its scope without call to $apply , because $emit already is in the digest cycle. Second, you only use $apply where is necessary. And third, you improve the performance by use $apply in scopes most small and with less children.

You could merge this answer with the answer of @sasko_dh

Maybe the Observer Pattern could be you useful.

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