I’ve noticed (some topics seem to suggest its only since version 1.1.0) that the ‘size’ of my scroll-area (eg. <ion-content>
) SOMETIMES does not update after elements change their size (width or height), for example if additional elements get shown via ng-show
.
According to the manual, this can be fixed by calling $ionicScrollDelegate.resize()
, but since I did not want to manually attach this behavior to any model-update that MIGHT trigger a element size change I implemented a simple watch directive on the height/width of an element.
app.directive('scrollSizeWatch', function($ionicScrollDelegate) {
return {
restrict: 'A',
link: function(scope, element, attr) {
var fetchValue = function() {
return {
width: $(element).width(),
height: $(element).height()
};
};
var valueChanged = function(value) {
$ionicScrollDelegate.resize();
//console.log('Size changed to', value);
};
scope.$watch(fetchValue, valueChanged, true);
}
};
});
The ‘funny’ thing I noticed is, that this still didn’t fix all occurances of this problem and a noticed that angular did not detect all size changes.
My guess is, that occasionally the size changed triggered inside some $scope.$apply()
(eg. by a ng-click
) actually happens after the $digest()
-cicle has finished, thus beeing unnoticed by angular.
(If someone could confirm my theory I’d be really happy…)
I implemented a workaround that will start a $timeout
during each $digest()
-cicle, that checks the elements size after a certain delay and calls $ionicScrollDelegate.resize()
if a change was detected.
(I don’t like this workaround, because it depends on the assumption that the updated size is known after a fixed amount of time after the $digest()-cicle started)
app.directive('scrollSizeWatch', function($ionicScrollDelegate, $timeout, scrollFixDelay) {
return {
restrict: 'A',
link: function(scope, element, attr) {
// Variables to store current state
var oldValue, promise;
/**
* Function: delayedCheck()
* Checks if the width or heights of the
* directives element has changed and
* updates the cached oldValue state.
*
* [SYNC]
*/
var delayedCheck = function() {
// Cache current value
var newValue = {
width: $(element).width(),
height: $(element).height()
};
// Compare old and current values
if (newValue.width != oldValue.width || newValue.height != oldValue.height)
$ionicScrollDelegate.resize();
// Update old values
oldValue = newValue;
};
/**
* Function fetchValue()
* This will be called multiple times during each $digest()
* phase by angular to detect changes.
*
* Note: Occasionally it can happen, that a change by angular
* can trigger a size (width/height) change of a html element.
* Rendering of such changes can sometimes happen after angulars
* $digest() cicle, which may cause angular to miss those changes.
* Workaround:
* Start a timer during the $digest() cicle that checks for changes
* after a certain amount of time has passed. Obviously this might
* break, if a $digest() cicle takes longer than scrollFixDelay
* milliseconds, but there does not seem to be a better solution.
*
* [SYNC & ASYNC]
*/
var fetchValue = function() {
// Cancel old timer and start new one (do not create a new digest cicle!)
$timeout.cancel(promise);
promise = $timeout(delayedCheck, scrollFixDelay, false);
// Return width/height information for angular to watch
return {
width: $(element).width(),
height: $(element).height()
};
};
/**
* Function: valueChanged()
*
*
* [SYNC]
*/
var valueChanged = function(value) {
$timeout.cancel(promise);
oldValue = value;
};
// Watch for height/width changes
scope.$watch(fetchValue, valueChanged, true);
}
};
});
Usage:
<ion-content>
<!-- NOTE: Fetching the size of an element, eg. via height(), for some reason does not work on custom elements (using scroll-size-watch on <my-directive> does not work), they'll always return 0 -->
<div scroll-size-watch>
<a ng-click="showBigText()">Show Text</a>
<span ng-show="bigTextVisible()">{{someBigText}}</span>
</div>
</ion-content>
(Sidenote: Besides using $ionicScrollDelegate.resize()
, scrolling all the way up/down and releasing touch also updates the scroll-area to the correct size, if that helps track down the issue.)