From the angular's documentation of $interval service:
invokeApply (optional) boolean: If set to false skips model dirty checking, otherwise will invoke fn within the $apply block.
Which can lead us to a conclusion that $rootScope.$apply wouldn't be called if I set invokeApply as false.
However, from the source of $interval I learned that deferred.notify is called each tick, which makes sense. What does not, is the fact that during deferred.notify execution $rootScope.$evalAsync is called, which in order calls $rootScope.$digest. So all the dirty checking still happens. Am I missing something here?
Bug already filed!
https://github.com/angular/angular.js/pull/5903
You are missing nothing
Related
I have a strange error and I am not sure what's happening.
When I check an object, I can see that the $valid tag is set to true (and $invalid shows false). But when I print out just that tag (such as object.$valid) it prints false (and object.$invalid prints true).
$scope.$watch('ctrl.form', form => {
console.log('The form is set to: ', form);
console.log('The form is valid: ', form.$valid);
});
Does anyone know why this might be happening?
I suspect the issue is, the values are still updating in that function; it is watching for a change in the value, but still hasn't applied the changed values. This can make your code in that handler unpredictable.
Since you mention applying the scope throws the "in progress" error, that seems to be valid (the digest is still working). This code frag checks for an in-progress digest and sidesteps it if necessary.
if ( ! $scope.$$phase ) {
$scope.$apply ();
}
Note that "$$" vars in Angular were "private". You could still access them but you're not "supposed" to. This does however have the benefit of not appearing as randomly vague as a zero timeout.
Alternatively, as you've already seen, a 0 timeout can force an update. That's a hack, but it does work and I've seen it used a few times.
Lastly, one of the lifecycle events may be a better choice for these traces, such that you know you're tracing information in the natural flow of the component, where digests are predictable.
Regarding that lifecycle hook, if you're using 1.5 (the last paragraph seems to fit right here and is probably what you want):
New: $onChanges
This new hook is similar to ng2’s ngOnChanges. It is called whenever one way bindings are updated, with a hash containing the changes objects.
Prior to this hook you sometimes had to use a $watch in order to do some work whenever a value you’re bound to changes. Using this hook makes things clearer and removes the need to introduce a watch and a dependency on $scope.
I'm having a problem debugging some code in an Angular controller. This function is called when a form is submitted on our checkout page. I'm fairly new to Angular, and I'm a bit confused as to what is going on in this function.
$scope.handleStripe = function(status, response){
PayStripe.processPayment(status, response).then(
function(successMessage){
alert('success', successMessage);
Order.recordOrder(Cart.cart.items, Auth.user.uid)
.then(function(){
PostAffiliatePro.reportSale(Cart.cart.getTotalPrice());
Cart.cart.clearItems();
$scope.mode = 'success';
});
}
);
};
Here's what I think is happening line-by-line...
1) We're declaring a function called handleStripe with two arguments: status and response.
2) A method called processPayment is being called and is inside of an object dependency injected into the controller called PayStripe. .then is opened, so the following lines of code will be executed AFTER the processPayment method is called.
3) Running an anonymous function with an argument of successMessage.
4) I'm confused as to what's happening here, as I've never seen alert called with any arguments other than a message. this page on alert is not much help.
5) A method called recordOrder is called from the object Order which is a dependency of the controller.
6-10) After the recordOrder method is called, the cart is cleared, the sale is reported through another method, and the mode variable contained in the controller's scope is updates to the value success.
I've looked through all of the methods associated with these steps, and I still have some questions.
1) Where are all of these arguments being passed in? Are the arguments passed into the functions pre-declared arguments that will be updated by Angular? I.E. are these variables which Angular defines as the process moves through the queue, and whose values are not user-defined?
2) On line #4, I understand that the second argument is from the argument defined in the function, but what is the combination of these two valued inside the alert() function doing?
3) The fix to the bug that comes from this script depends on me being able to change the value of $scope.mode to something different as soon as the handleStripe function is called, however I have tried to insert such a declaration in multiple places that seem logical with results varying from the script breaking, to nothing happening at all. To me it seems that the logical place to put $scope.mode = 'my-value'; would be between current lines #1 and #2, however this produces the affects I mentioned before.
Finally, I feel I may be missing an overall concept, rather than wrestling with syntax. What is this concept called, if I am missing one, and where can I learn to use it?
I'm playing around with handling the query string on page load, and noticed something about $watch.
It looks like it takes some time for $watch to register when it is called - and this process is asynchronous.
I'm finding that I have to deal with race conditions as my $watch does not trigger when it should - that is, values that are set after the $watch declaration do not get evaluated by the $watch.
See this example for an illustration of the problem: http://jsbin.com/kapifezi/24/edit
Does anyone have a best practice around using watches to avoid this type of issue?
As it turns out - after investigating further - I didn't fully understand how $watch worked.
http://angular-tips.com/blog/2013/08/watch-how-the-apply-runs-a-digest/ really helped shed some light on the situation.
As it turns out - simply changing a variable that is being watched won't trigger a digest loop by itself.
The reason $timeout worked was because it "safely" makes a call to $digest which causes all $watch expressions to be evaluated - that is, it was the $digest component of the $timeout that caused the $watch to fire and not the wait of 1000 milliseconds.
Lesson learned.
do you mean value updated inside $timeout??? there will be 1000 miliseconds delay before $scope.val is changed to 1 inside $timeout and after that $scope.val gets updated
Not really got what do you mean but in my controller if I need watch for some var im doing this:
$scope.myValue = "value";
$scope.$watch("myValue", function(val) {
if (val) {
console.out(val);
}
});
I'm writing a plugin based on this handy template for class-based CoffeeScript jQuery plugins: https://gist.github.com/rjz/3610858
Everything works pretty well. However, there is some unexpected behavior at the end when I register the plugin:
$.fn.extend markdownAsides: (option, args...) ->
#each ->
$this = $(this)
data = $this.data('markdownAsides')
if not data?
$this.data 'markdownAsides', (data = new MarkdownAsides(this, option))
if typeof option is 'string'
data[option].apply(data, args)
data # Plugin breaks without this line
Before I added that final line (a solution I discovered purely on accident), the initial construction of the plugin worked fine, but on successive method calls, the jQuery each loop sometimes failed to iterate through every element.
Checking this.size() outside the each loop returned the correct value, and checking individual elements outside the loop also looked fine. But inside the loop, elements would sometimes be skipped, in a pattern I could not discern.
Like I said, the problem is fixed by adding the final line. (Perhaps the return value of the function being passed to each matters somehow?) My question isn't "how do I fix this?" but "why does this work?"
Returning false from the callback function passed to each will break out of the loop. I haven't verified but perhaps jQuery will also break on any falsey value except undefined.
Since in CoffeeScript there's an implicit return, you were possibly returning something falsey or even false from the callback depending on the operation performed in it.
To avoid any issues, just change data for true at the end.
I have problems when a I call a function that calls the other function that keep calling back until a puzzle is solved or find no moves.
The thing is that I need to call a function twice but with different values.
I tried storing the values, but as soon as I call the second function wchich calls back, it overrides the values.
the most important pieces of code are here:
function splitways(){
var strsp,aa=dir,bb=xy;
if(nextRock()){
if(xy!=start){
strsp=(aa+""+bb+""+dir+""+xy)*1;
if(!(strsp in arr)){
arr[strsp]=strsp;
caller(dir,xy);
}
}else{
count++;
}
}
}
function caller(num,pos){
var aa=num,bb=pos;
splitways();
//--
dir=aa;
xy=bb;
//--
dir==1?dir=4:dir--;
splitways();
}
Notes, splitways() changes the values of dir and xy, that is why I tried to change them back and then modifing them before the second call to splitways(). But with the first call everything is erased.
I tried everything I can for 2 hours... The best shot I had was to cache them on var aa=num,bb=pos; but that didn't work.
Any ideas are appreciated
Although I'm not entirely sure what you are trying to do with your code, I think you have some of your logic mixed up:
On the first call (I assume you are calling splitways() first), you set "aa=dir" (lets only pay attention to this). When "caller()", it takes the global variable "dir", obviously. Now, in "caller()", you set "aa=num" which translates to "aa=dir". You call splitways again, which then does the exact same thing: "aa=dir". This continues constantly (AKA: until caller() is stopped being called). However, as it goes back through the execution stack, you have, in "caller()", "dir=aa". Now, you already did "aa=num", so "dir=aa" does absolutely nothing since you haven't changed the value of "dir" anywhere that has executed yet.
Eventually, the LATEST "caller()" call will execute the "dir==1?dir=4:dir--" line, but when that function finishes and the execution returns to the SECOND TO LAST "caller()" call, it resets "dir=aa", so dir is never actually changed until the VERY last call (the first "caller()" execution that happened).
If that made absolutely no sense, good. There has got to be a better way for you to do what you are trying to do. Maybe I can help with that?