I'm trying to work more with directives to apply a bit more best practices but I have some questions on the best way to apply a scope value from a directive.
In this fiddle demo, you can see if you click on the "Toggle displayMenu " button, the div is still toggled on. If you toggle lines 7-8 in directive's code :
scope.yolo = function () {
scope.ctrl.toggle(); // COMMENT ME
//scope.ctrl.toggleApply(); // UNCOMMENT ME
};
to :
scope.yolo = function () {
//scope.ctrl.toggle(); // COMMENT ME
scope.ctrl.toggleApply(); // UNCOMMENT ME
};
the displayMenu div will toggle off.
Now, the problem is I am forced to write 2 functions, one with "$scope.$apply" and one without, and it is clearly not a smart way to do it... unless I use safeApply like :
$rootScope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
Is the safeApply is the best practice ? If not, what is the best way to acplish what I want ?
I'm trying to work more with directives to apply a bit more best practices but I have some questions on the best way to apply a scope value from a directive.
In this fiddle demo, you can see if you click on the "Toggle displayMenu " button, the div is still toggled on. If you toggle lines 7-8 in directive's code :
scope.yolo = function () {
scope.ctrl.toggle(); // COMMENT ME
//scope.ctrl.toggleApply(); // UNCOMMENT ME
};
to :
scope.yolo = function () {
//scope.ctrl.toggle(); // COMMENT ME
scope.ctrl.toggleApply(); // UNCOMMENT ME
};
the displayMenu div will toggle off.
Now, the problem is I am forced to write 2 functions, one with "$scope.$apply" and one without, and it is clearly not a smart way to do it... unless I use safeApply like :
$rootScope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if(phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
Is the safeApply is the best practice ? If not, what is the best way to acplish what I want ?
Share Improve this question asked Mar 11, 2016 at 0:02 Jacques CornatJacques Cornat 1,6521 gold badge20 silver badges35 bronze badges1 Answer
Reset to default 8Looking at the $$phase
is considered bad practice. From a similar topic the angular devs have said that:
For future-proofing reasons, you should not use $$phase
The remended best practice is to either use $timeout or $evalAsync which both defer the execution of the code. In essence, both functions will be executed in a new $digest cycle so you don't have to manually call $apply yourself. Most of the time you can probably use $evalAsync if you just need to update some code in a safeApply scenario.
scope.$evalAsync(function(scope) {
// run the toggle function without caring if you're in the digest or not
scope.ctrl.toggle();
});
You can read this article by Ben Nadal to see how the different functions get executed in the JavaScript process.