Getting error while calling angularjs function - angularjs

while calling function getting this error
Error: "[$rootScope:inprog] http://errors.angularjs.org/1.6.9/$rootScope/inprog?p0=%24digest"
But if calling it from console it is working fine.
angular.element('body').scope().set_active_counter(1);
And function looks like this
$scope.set_active_counter = function (i) {
$scope.$apply(function () {
$scope.active_question_counter = i;
});
active_question_counter = i;
}

"inprog" typically means there's a digest in progress. Calling $scope.$apply() manually is the cause. The only time you should ever need to manually call $scope.$apply() is if it's inside some kind of async-ish call like the callback from $http or a promise.
Assigning a value to the $scope variable "active_question_counter" should automatically trigger a digest. But because you have manually triggered the digest, and within the scope of that digest you are making the change, the result is a "digest already in progress" error.
You shouldn't need to explicitly call $apply() here unless there's some weird behind-the-scenes linking going on that doesn't actively detect that something has changed. If that is the case, a hacky workaround is to wrap the $scope.$apply(...) inside a setTimeout().
I'm not really sure why executing this through angular.elment().scope() in the console works. Maybe the console is running in a separate context?

Related

Can I tell why Angular 1 is calling a rootScope function on every digest

I am having an issue where I have a function like this...
$rootScope.canNavigate = function(stateName) {
return !stateName || Authentication.canNavigate.call(Authentication, $state.get(stateName));
};
The problem is this function gets called continuously. The stack trace is different every time but has one thing in common, it is always coming from $apply. I have commented out all of the watches that are using this function and it is still happening. Does anyone know why this is happening? I cannot seem to reproduce in a plunker.
Asiel probably has the right answer depending on your situation, but as to how to prevent it, you can either use the bind once expression as Asiel suggests or, if that's not possible for some reason, you could also save the results so you're not calling that service every time.
var canNavigateCache = {};
$rootScope.canNavigate = function(stateName) {
return !stateName
|| canNavigateCache[stateName]
|| canNavigateCache[stateName] =
Authentication.canNavigate.call(Authentication, $state.get(stateName));
};
This also gives you the ability to clear the cache if you need to by just resetting the cache object (canNavigateCache = {})
If there is a call of this function on any of your html, this function will be called every time angular executes a digest cycle in order to do dirty checking (See this question on SO in order to get some kind of reference about this)... except you use the bind once expression (See syntax on this article and this on SO)
It is called from $apply because
$apply() is used to execute an expression in angular from outside of
the angular framework. (For example from browser DOM events,
setTimeout, XHR or third party libraries). Because we are calling into
the angular framework we need to perform proper scope life cycle of
exception handling, executing watches.
but $apply is (also) used by the own framework for making a digest cycle.

angularjs: $apply(fn) better than $apply()

I am reading
http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/
directive link function:
element.bind('click', function() {
scope.foo++;
scope.bar++;
scope.$apply();
});
a better way for using $apply:
element.bind('click', function() {
scope.$apply(function(){
scope.foo++;
scope.bar++;
});
});
What’s the difference? The difference is that in the first version, we are updating the values outside the angular context so if that throws an error, Angular will never know. Obviously in this tiny toy example it won’t make much difference, but imagine that we have an alert box to show errors to our users and we have a 3rd party library that does a network call and it fails. If we don’t wrap it inside an $apply, Angular will never know about the failure and the alert box won’t be there.
Confusion:
Why angular need to know error, i just need to show it for users. for example, there is an ajax request in link fn of directive, I just need to tell what happened if fails.
TAngular $scope has a function called $apply() which takes a function as an argument. AngularJS says that it will know about model mutation only if that mutation is done inside $apply(). So you simply need to put the code that changes models inside a function and call $scope.apply(), passing that function as an argument. After the $apply() function call ends, AngularJS knows that some model changes might have occurred. It then starts a digest cycle by calling another function —- $rootScope.$digest() — which propagates to all child scopes. In the digest cycle watchers are called to check if the model value has changed. if a value has changed, the corresponding listener function then gets called. Now it’s upto the listener how it handles the model changes.
The Ajax call through Angular buildin $http the model mutation code is implicitly wrapped withing $apply() call, so you don’t need any additional steps.

Why does $timeout delay the whole page loading inside $ionicView.Enter?

As far as i know, $timeout is a promise object in angular, which means the code will go on running without waiting for the timeout to end.
However, when i used it in my ionic code, for some reason it did and the whole loading of the page froze for 6 seconds. Can you please explain why?
$scope.$on("$ionicView.Enter", function( scopes, states ) {
$timeout(function(){
// some function i wrote
}, 6000);
});
Your assumption around the code continuing to run is wrong - otherwise what would the point of calling $timeout be? It's an Angular wrapper and recommended to use in place of window.setTimeout() but works exactly the same. The code above will execute after a 6000ms delay.
[ADDED] From the Angular API docs: "The return value of calling $timeout is a promise, which will be resolved when the delay has passed and the timeout function, if provided, is executed."

What is $$phase in AngularJS?

I found this code snippet which is part of a angular directive someone wrote for bootstrap modal.
//Update the visible value when the dialog is closed
//through UI actions (Ok, cancel, etc.)
element.bind("hide.bs.modal", function () {
scope.modalVisible = false;
if (!scope.$$phase && !scope.$root.$$phase)
scope.$apply();
});
I understood that this part is for the latter half of two way binding we bind to hide.bs.modal event and update modal when UI changes.
I just wanted to know why is the person checking $$phase for scope and rootScope before calling apply ?
Can't we straightaway call apply ?
What is $$phase here?
I tried searching a lot, couldn't find any good explanation.
EDIT:
I found where I saw the example:
Simple Angular Directive for Bootstrap Modal
$$phase is a flag set while angular is in a $digest cycle.
Sometimes (in rare cases), you want to check $$phase on the scope before doing an $apply. An error occurs if you try to $apply during a $digest:
Error: $apply already in progress
Davin is totally correct that it's a flag that angular sets during the digest cycle.
But don't use it in your code.
I recently got a chance to ask Misko (angular author) about $$phase, and he said to never use it; it's an internal implementation of the digest cycle, and it's not future safe.
To make sure your code continues to work in the future, he suggested wrapping whatever you want to "safe apply" inside of a $timeout
$timeout(function() {
// anything you want can go here and will safely be run on the next digest.
})
This comes up a lot when you have callbacks or other things that might resolve during the digest cycle (but don't always)
Here's an example snippet from when I was dealing with one of google's libraries: (The rest of the service this was from has been left off.)
window.gapi.client.load('oauth2', 'v2', function() {
var request = window.gapi.client.oauth2.userinfo.get();
request.execute(function(response) {
// This happens outside of angular land, so wrap it in a timeout
// with an implied apply and blammo, we're in action.
$timeout(function() {
if(typeof(response['error']) !== 'undefined'){
// If the google api sent us an error, reject the promise.
deferred.reject(response);
}else{
// Resolve the promise with the whole response if ok.
deferred.resolve(response);
}
});
});
});
Note that the delay argument for $timeout is optional and will default to 0 if left unset ($timeout calls $browser.defer which defaults to 0 if delay isn't set)
A little non-intuitive, but that's the answer from the guys writing Angular, so it's good enough for me!
In that example, the element binding will get executed from a non-angular event. In most cases, it is safe to just call $apply() without checking the phase.
If you look at the rest of the code, however, there is a $scope function called showModal(). This function calls into the non-angular code which will likely cause a "hide.bs.modal" event to fire. If the event fires via this route, then the call stack is within a $digest.
So, this event does fall within the rare case of a function that will get called from both angular-managed code AND non-angular code. Checking the $$phase in this case is necessary because you don't know how the event originated. If the $$phase is set to something, then the digest loop will finish to completion and $apply() doesn't need to be called.
This pattern is often referred to as "safe apply".
my understanding is it is good to use when digesting or applying the scope. If it is truthy it means that there is currently a $digest or $apply phase in progress. If you are getting related errors you can do $scope.$$phase || $scope.digest(); which will only digest if $scope.$$pahse is falsy.
You can use $scope.$evalAsync() method rather than using the $scope.$apply() externally with the $$phase value check as rightly suggested by #betaorbust:
I recently got a chance to ask Misko (angular author) about $$phase, and he said to never use it; it's an internal implementation of the digest cycle, and it's not future safe.
The good thing about $scope.$evalAsync() is that it gives you what you really want, get the fresh data up with the digest cycle, faster than even the $timeout can:
Up until now, my approach to deferred-$digest-invocation was to replace the $scope.$apply() call with the $timeout() service (which implicitly calls $apply() after a delay). But, yesterday, I discovered the $scope.$evalAsync() method. Both of these accomplish the same thing - they defer expression-evaluation until a later point in time. But, the $scope.$evalAsync() is likely to execute in the same tick of the JavaScript event loop.
Usage is quite simple:
$scope.$evalAsync(
function() {
// Call some method here OR
$scope.excutemyMethod();
// assign some value;
$scope.someVariable = "asd"
}
);
The method inside the $evalAsync() is added to the Async queue so that it can be executed in the following digest cycle by internally triggering $apply which is what we really want.
Also it includes the $timeout call to handle rarest of rare scenarios watching for the async queue length and waiting the tasks in the Async Queue to be executed to put your function in the execution cycle as soon as possible. Refer Ben Nadel blog, which explains this fact.

AngularJS's $scope.watch function is not firing on data modification

You can see the problem in this plunk with Chrome or FireFox's console open:
http://plnkr.co/edit/jmDcxqQ48PmeHt3EPVMU
When you click "Push!" for the first time, the watch function doesn't execute. But if you push it again, it does execute. It's like it ignores the first push. However, you can clearly see the dataPoints array changes after the first push due to the timeout function that is executing in the background. What's weirder, is if you comment out the jQuery fadeIn wrapper, the code works as expected (the watch function is executed on the first button push).
What's going on here? Why is the $watch function not executing when jQuery().fadeIn is used?
jQuery('#mytest').fadeIn(200, function() {
$scope.mydata.dataPoints.push(1);
$scope.$$phase || $scope.$apply();
})
When the fadeIn callback runs, it runs "outside" Angular, so we need to call $scope.$apply() to run a digest cycle. However, if the object is already visible, it seems that jQuery runs the callback immediately (so we're still "inside" Angular), so we don't need to (and shouldn't) call $scope.$apply().
The easy way to handle both cases is to check to see if we are already in a digest cycle using private property $$phase. A cleaner implementation would be to not call fadeIn() if the div is already visible.

Resources