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

Partial $digest for scope subtree #5583

Closed
artch opened this issue Dec 31, 2013 · 13 comments
Closed

Partial $digest for scope subtree #5583

artch opened this issue Dec 31, 2013 · 13 comments

Comments

@artch
Copy link
Contributor

artch commented Dec 31, 2013

I think it could be useful to have a possibility not to perform the overall $digest loop, but only on the specific scope subtree when some watchers are triggered. OFC optionally and on developer's own risk, when he does know exactly which scopes are affected by the change and which are not.

@anvarKhakimov
Copy link

+1

@caitp
Copy link
Contributor

caitp commented Jan 20, 2014

This is already possible, I believe. However $scope.$apply() calls $rootScope.$digest(), which is probably the root of this issue.

... hmmm, $digest sets the phase of the root scope, but it starts looking at the async queue and watchers from the current scope and traverses down the hierarchy.

So it's sort of a mix of supported and not. interesting :>

@tonypee
Copy link

tonypee commented Feb 3, 2014

This would need to be combined with a way to supress digest on the tree in general, or it would all too often be processed. I was thinking that a directive could cause the general digest loop to break out of a tree? eg: something like ng-sleep="true"

This would allow sections of your application could be disabled, for performance. Maybe you could even trigger an update on them on demand?

@guillaume86
Copy link

+1
It would be useful for directives requiring high frequency updates (progressbars, hover effect...).
At the moment I've to replicate angular functionality in jQuery to avoid trigerring full $digests and keep decent performance.

@dusanbartos
Copy link
Contributor

+1

@artch
Copy link
Contributor Author

artch commented Apr 24, 2014

More on this subject from React library -- an elegant algorythm to perform diff only on the changed subtrees: http://calendar.perfplanet.com/2013/diff/

@IgorMinar
Copy link
Contributor

you can do this already by calling someScope.$digest();

example: http://plnkr.co/edit/tV8kihZrm3hG3w7Fneq2?p=preview

the issue is that most of entry points into Angular apps (event directives, etc) correctly call $apply which always triggers full digest.

@kseamon has some tricks that temporarily rewrite scope hierarchy to reparent $rootScope with the current scope only. While clever, it's a nasty solution.

Would it make sense to somehow target this only at isolate scopes and then provide a way for isolate scopes to overwrite what $rootScope in their context means, so that $rootScope for isolate scopes is still the main isolate scope of the component.

This way components could opt-into partial digests. We'd still need to figure out how to propagate model updates from such component to the rest of the application in a sane way.

@kseamon
Copy link
Contributor

kseamon commented May 20, 2014

The most annoying part of my $apply isolation hack is that when you want to trigger a dirty check higher up you need to use $timeout since you're already in a digest loop within your own scope so direct calls to $rootScope.$apply will not work.

Also, it would be nice to have $applyLocal in addition to $digest to add on the $eval and try/catch functionality of $apply missing from $digest.

@IgorMinar
Copy link
Contributor

$applyLocal will work only for calls that are explicitly local. We need a solution that will work for all directives used in this isolated context (e.g. ngClick).

We could create something like a $localRootScope which if set, would be used by $apply instead of $rootScope.

@kseamon
Copy link
Contributor

kseamon commented May 21, 2014

I didn't mean to suggest $applyLocal solves this issue–it would just be nice to have.

Just to check, you're proposing that $localRootScope is a boolean that can be toggled at any time, or something that would be set by $new()?

Also, to one of my earlier points, it would be very helpful if there was a way to "promote" a local digest (or an isolated one) to a full-page one without using $timeout (e.g. synchronously). At present, calling $rootScope.$digest/$apply from within the context of a local digest throws an exception.

@tbosch
Copy link
Contributor

tbosch commented Aug 20, 2014

See this PR for a try: #8055

@tbosch
Copy link
Contributor

tbosch commented Aug 20, 2014

We are going to close this issue.
Reasoning:

  • localApply would not work together with promises
  • localApply would not work with directives that have an isolate scope and change the bindings (e.g. a custom checkbox)
  • if a user enabled this, its hard to detect whether it really worked correctly. We would need a debug mode which does a second digest to check that nothing outside of the localApply scope was modified

To summarize, this would be doable and some use cases would benefit, but the maintenance costs would be high (i.e. when problems need to be debugged), and there are already workarounds if you really know what you are doing :-)

@tbosch tbosch closed this as completed Aug 20, 2014
@lord2800
Copy link

Could there be some documentation updates on these workarounds? With a note about the dangers/etc?

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