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