Ion-content can't scroll after loading new content on Android


#1

In my app I have a ion-content element an accordion (based on this CodePen: http://codepen.io/ionic/pen/uJkCz). In my particular case the accordion has 4 items and does not take up the whole screen. Due to native Android behaviour this content can’t be scrolled because all content fits in the view. When I click on one of the items, the accordion slides down/open with multiple items. This makes the ion-content element no longer fit in the viewport entirely.

However, when I try to scroll on Android nothing happens. As soon as I lift my finger from the screen (or ion lab) and try again it magically works.

I would like to reproduce this problem by forking the accordion codepen, however, I don’t know how force the platform-android for the pen.

A quickfix I found was to add has-bounce=“true” to my ion-content, which makes it behave like iOS: always enabling scroll. However, I would like the solve it the right way…

As far as I can tell somehow the ion-content needs to take into account the change of the accordion, similarly to calling the apply function in Angular. But because this doesn’t happen, scrolling doesn’t work. Once I tried scrolling the first time, somehow a scroll/content event is fired and only then the ion-content takes the new changes into account.

TLDR;

  1. how do I force platform-android into CodePen
  2. how do I tell ion-content its view got updated?

Thanks!


#2
  1. You can add this script tag before the end of the body to trick codepen into thinking it is an android:

     <script>
       ionic && ionic.Platform && ionic.Platform.setPlatform("android");
     </script>
    
  2. You should use $ionicScrollDelegate.resize() in the function toggleGroup. You may need to wrap it in a $timeout to ensure it happens after the elements are displayed.

     $timeout(function() {
        $ionicScrollDelegate.resize();
     }, 100);
    

#3

@brandyshea Thank you so much! With your help I was able to both reproduce the problem with CodePen and fix it: http://codepen.io/anon/pen/WvGGvg

Update: I went a little crazy and explored some ‘better options’ because as a general rule I dislike using timeouts unless I really have to:

Quick and dirty fix, but breaks if your transition takes longer then 100 ms:

$timeout(function() {
    console.log('called resize');
    $ionicScrollDelegate.resize();
}, 100);

It’s possible to get the transition duration. Note: you will still need to parse this string to a valid number in milliseconds:

angular.element(".item-accordion").css('transition-duration');

If you really want to go nuts, bind the transitionEnd event to the elements which are called once the animation is complete. However you need define and cancel the times because the ionicScrollDelegate will be called multiple times… You also need to add jQuery, because this will not work with jQlite!
http://stackoverflow.com/a/13582380/443547

var timer;
angular.element(".item-accordion").one('transitionend webkitTransitionEnd oTransitionEnd otransitionend MSTransitionEnd', 
    function() {
        $timeout.cancel(timer);
        timer = $timeout(function() {
            console.log('fake calling resize event');
        }, 100);
    });

I expect to just be using the simple $timeout option provided by @brandyshea because this keeps the code most simple and readable. All I have to do is make sure I don’t change the duration of my animations.


#4

Very nice research. Thanks for sharing. :slight_smile: