We're building a single page application which has multiple pages loaded as tabs. Only the content of one tab is visible at any given time (much like a browser), so we want to temporarily pause $digest
and watchers from executing on those DOM nodes of the hidden tabs, until the user switches to that tab.
Is there a way to achieve this, so that the model continues to be updated for the background tabs, but the view updates based on a condition.
The following code illustrates the problem:
<div ng-repeat="tab in tabs" ng-show="tab.id == current_tab.id">
<!-- tab content with bindings -->
</div>
The goal is optimization.
I'm already aware of Scalyr directives, but I want a more specific solution without the extra features contained in Scalyr.
After some trial and error I've figured out the following directive which pauses all the children's $$watchers
if the expression on the attribute evaluates to true
, on false
it restores any backed up $$watchers
app.directive('pauseChildrenWatchersIf', function(){
return {
link: function (scope, element, attrs) {
scope.$watch(attrs.pauseChildrenWatchersIf, function (newVal) {
if (newVal === undefined) {
return;
}
if (newVal) {
toggleChildrenWatchers(element, true)
} else {
toggleChildrenWatchers(element, false)
}
});
function toggleChildrenWatchers(element, pause) {
angular.forEach(element.children(), function (childElement) {
toggleAllWatchers(angular.element(childElement), pause);
});
}
function toggleAllWatchers(element, pause) {
var data = element.data();
if (data.hasOwnProperty('$scope') && data.$scope.hasOwnProperty('$$watchers') && data.$scope.$$watchers) {
if (pause) {
data._bk_$$watchers = [];
$.each(data.$scope.$$watchers, function (i, watcher) {
data._bk_$$watchers.push($.extend(true, {}, watcher))
});
data.$scope.$$watchers = [];
} else {
if (data.hasOwnProperty('_bk_$$watchers')) {
$.each(data._bk_$$watchers, function (i, watcher) {
data.$scope.$$watchers.push($.extend(true, {}, watcher))
});
}
}
}
toggleChildrenWatchers(element, pause);
}
}
}
});
Ok, the reason I asked you to show some code was because of the reason @Rouby stated.
For performance purposes, you can use ng-if
instead of ng-show
. ng-if
removes or restores the element from the DOM.
<div ng-repeat="tab in tabs" ng-if="tab.id == current_tab.id">
<!-- tab content with bindings -->
</div>
ng-show
is good to use when you want to style the hiding differently. For instance, you might want that a hidden element would only have its "body" hidden, with the header still appearing. It is possible with ng-show, you just have to define a CSS style for the class ng-hide
.
If you want to keep the values of your $scope, you can bind those with a parent scope who would keep your variables intact.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With