Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

As a big project developper, I want to use only $digest instead of $apply #7298

Closed
XavierBoubert opened this issue Apr 29, 2014 · 11 comments
Closed

Comments

@XavierBoubert
Copy link

In a big project containing a central page with many features, it's not possible to refresh the entire page with $apply everytime because of working time for filters, $watchers, etc. We need to refresh just parts of the UI and it's okay because we are the developers and have the control of these. $apply is not designed for big projects.
So, maybe I'm wrong but I think we really need to change the behavior of AngularJS dirty-checking updates. We need to use $digest most of the time and $apply rarely. For me, ng-click should call the $digest of the current scope and not for the $rootScope, like all of the ng- directives and $http, ectc.

I have wrote a big post on the subject with examples to explain why: https://groups.google.com/forum/#!topic/angular/tswtLq9xbwU

@quantizor
Copy link

Have you checked out $evalAsync? I've used it in the past to avoid $apply and it propagates changes nicely without thrashing all the watchers.

@XavierBoubert
Copy link
Author

It does not solves the problem with directives ng-* that call $apply.
It does not solves the problem with second $digest in other part of view because $evalAsync call only $eval inside the next $digest().

So if we call a $digest() inside a directive and we want to digest an other directive, $evalAsync will only be used to refresh the first directive.

Try this fork of my example with $evalAsync : http://jsfiddle.net/xavierboubert/NB6YS/

@XavierBoubert XavierBoubert changed the title Has a big project developper, I want to use only $digest instead of $apply As a big project developper, I want to use only $digest instead of $apply Apr 30, 2014
@darlanalves
Copy link

I was thinking about a flag on $apply() to restrict the scope where it starts. What about a $apply(true) to keep the functionality of $apply (e.g. error handling) and restrict the scope where it starts firing, like $digest would do?

It's just an example. I know $apply receives an expression to evaluate before start the $digest cycle, which can be both a string or a function. It would only work if the first parameter is strictly true (e.g. === true).

What do you think? Pros and cons?

@XavierBoubert
Copy link
Author

Would not it be better than when starting a digest it does not block the $$phase of its parents?

I don't understand the differences between tour $apply(false) and $digest().

@caitp
Copy link
Contributor

caitp commented May 9, 2014

$apply is just $rootScope.$digest, nothing more, there is no difference (with the exception that it will optionally eval an expression first)

@XavierBoubert
Copy link
Author

@caitp Do you have ideas for the subject of this post?

@mebibou
Copy link

mebibou commented May 9, 2014

@darlanalves I don't understand what you're proposing, if you only want to put a flag in $apply to behave like a $digest, what's the point of using $apply instead of $digest?

@XavierBoubert
Copy link
Author

For more informations, we are talking about the subject with Ben Nadel: http://www.bennadel.com/blog/2625-triggering-digest-phases-in-related-directives-in-angularjs.htm

@darlanalves
Copy link

@mebibou Sorry, I misunderstood it. I was assuming that $digest would not have error handling, but it's only needed if you actually evaluate something, which in turn is the only difference from $apply and $digest. As @caitp said, there's no difference, except that $apply starts on the $rootScope, so back to $digest instead of $apply.

@caitp
Copy link
Contributor

caitp commented May 9, 2014

In particular, it's more like

try {
  scope.$eval(someExpression); // if you want to evaluate an expression first
} catch (e) {
  // tell $exceptionHandler if you want to, otherwise you could just ignore it or log it
} finally {
  // digest regardless of whether there was an error or not.
  scope.$digest();
}

That's pretty much an exact match for $apply(), without touching scopes that you don't consider important

@gkalpak
Copy link
Member

gkalpak commented Jun 8, 2016

At this point, I don't think it is reasonable to consider changing the framework's internal $apply calls to $digest calls, as that would be a huge breaking change (of course you are free to use $digest in your own directives/services if you understand the implications).

FWIW, Angular 1 applications have been designed with that assumption for years and breakages for such a change would be too difficult to test for and debug (especially for large apps).

Furthermore, most calls to $apply inside the codebase are on the $rootScope, which means that there is no overhead compared to $digest.
The few places that $apply is called on a child scope is for directives (e.g. ng-event-*, ng-model) and I believe that it is the correct behavior: A change in an input's value is likely to affect much more than it's closest scope (escpecially if wrapped in an ngIf/ngSwitch or being part of a custom control component directive). Similar for a click handler.

That said, if anyone has a compelling usecase for using $digest in ngClick or any other directive, you can always overwrite it (although I wouldn't recommend it) or create your own.

This feature is certainly not suitable for most apps (thus not suitable for core) and the overhead of rolling out your own ngClick directive for a big project is minimal.

Closing this as won't fix/not core.

@gkalpak gkalpak closed this as completed Jun 8, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

8 participants