Slide-box Dynamic Height

I’m not sure I understand what the problem is either. So, a CodePen sample would help.

On the new version of the ionic it works

Line 20 I added {{$index}}, if you remove that line, the second slide’s content doesn’t show up.

I am not sure why it works with “pictures”, but when I build my slides by using “ng-repeat”, for all slides the height will be taken from the longer slide (even if I call update at the end)
Do you have any examples with 2-3 slides with different height built by utilizing ng-repeat ?
Thanks

Given a long text string, how can I paginate it across multiple slides? The number of characters per page is determined by container dimensions (responsive) and character font.

Is there a way to determine the height of the slide? Maybe, it is the screen height minus header and footer.

I’m sorry, but these are terrible solutions. You take a pretty big UX hit by hiding the pages during transitions. Kind of kills the joy of the slidebox. You could get around this by waiting until the transition is finished to hide, resize, and unhide, but these seems like an awful lot of work for something conceptually simple.

I am just getting started with Ionic and I am loving it so far, but this seems like one of those little weird spots.

Why can’t we just put tags inside a slide and get a nicely contained scrollable container? That is the way I would want it to work.

Anyway, thanks to the team for allt he great work and for the folks out there answering questions… it’s too late and I must go to bed. Would like to keep on playing. :smile:

Agreed. Hiding adjacent slides defeats the purpose of a slide box, essentially turning it into a swipe box.

Trying to find a workaround, as the extra space below short slides looks horrible. One hack that comes to mind is to reset the heights of all slides to the height of current slide whenever slide is changed/loaded, so that the extra content in other slides may overflow, or be hidden, and be displayed when they are the focused slide. Struggling with implementation of this hack though, if anyone gets any ideas on how to do this, please do share.

All right folks, seems like my pretty little hack is working.
Here’s a [codepen demo][1] .

Instructions:

  1. Add the following directive peey-level-ion-slides to the ion-slide-box
    containing variable height slides
  2. Wrap up content in your ion-slide with a div with a class, and add the same class with -active suffix to the active slide’s wrapping div (ionic is missing the feature of adding a special class to the active slide so you have to do this yourself for now using ng-class, will add a feature request on ionic’s github for this).
  3. Lastly you add a slide-child-class attribute on ion-slide-box and its value should be the class that you have chosen for wrapping divs, and you’re golden!

Here’s the hero directive:

 .directive('peeyLevelIonSlides', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            scope.$watch (
                function () {
                    var activeSlideElement = angular.element(element[0].getElementsByClassName(attrs.slideChildClass+"-active"));
                    //constantly remove max height from current element to allow it to expand if required
                    activeSlideElement.css("max-height","none");
                    //if activeSlideElement[0] is undefined, it means that it probably hasn't loaded yet
                    return angular.isDefined(activeSlideElement[0])? activeSlideElement[0].offsetHeight : 20 ;
                },
                function (newHeight, oldHeight) {
                    var sildeElements = angular.element(element[0].getElementsByClassName(attrs.slideChildClass));
                    sildeElements.css("max-height",newHeight+"px");
                }
            );
        }
    }
})

I’ll add more info soon, if required
[1]: http://codepen.io/peey/pen/zLIka

1 Like

Very nice, peey. This appears to be working well in the Codepen. I haven’t looked closely yet, but do you think there are any issues with using async data here and updating the Slide box with $SlideBoxDelegate.update()?

The active slide is allowed to freely change its height, so I think it should be okay. I’m using it for dynamic height content myself, and it seems to be working quite nicely!

Probably a better solution than this hack is to put ion-content inside ion-slide - see codepen at Vertically scroll-able lists/contents in ion-slidebox .

1 Like

A slight addition to @peey’s directive that I found necessary on iOS in case anyone else ends up here:

angular.module('snaps').directive('snSlideBox', function ($timeout, $ionicScrollDelegate) {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      function resize () {
        $ionicScrollDelegate.resize()
      }

      scope.$watch(function () {
        var activeSlideElement = angular.element(element[0].getElementsByClassName(attrs.slideChildClass + "-active"))
        activeSlideElement.css('max-height', 'none')

        return angular.isDefined(activeSlideElement[0]) ? activeSlideElement[0].offsetHeight : 20
      }, function (newHeight) {
        var sildeElements = angular.element(element[0].getElementsByClassName(attrs.slideChildClass))

        sildeElements.css('max-height', newHeight + 'px')

        resize()
        $timeout(resize)
        $timeout(resize, 50)
      })
    }
  }
})

I agree with @JonathanAquino. Better to be using ion-content inside of ion-slidebox. At the time I did not completely understand the working of ion-content and went with the copy paste code. I’m using the described setup in a production app with another slidebox implementation and things are pretty neat, and I think it should work all the same in ion-slidebox

In the latest nightly build using ion-content inside of a slidebox really messes up the height of the slidebox. I think with the beta-14/1.0 refactoring this is no longer proper (although then there’s no way to properly size lists of different lengths/heights in multiple slides in a slidebox).

For anyone still having issues with dynamic or asynchronous slides, I have an awesome directive.

<ion-slide ng-repeat="feature in featured" dynamic-slides="featured">
    <div ng-bind-all-html="feature.content"></div>
</ion-slide>
module.directive('dynamicSlides', function() {
    return {
        require: ['^ionSlideBox'],
        link: function(scope, elem, attrs, slider) {
            scope.$watch(function() {
                return scope.$eval(attrs.dynamicSlides).length;
            }, function(val) {
                slider[0].__slider.update();
            });
        }
    };
});
1 Like

And to complete the implementation, this will make the slide box adjust to the slide height (so long as the slide takes up space eg. no absolute positioning)

CSS:

.slider-slide {
    height: auto;
}

HTML:

<ion-slide-box dynamic-height>
    <ion-slide ng-repeat="slide in slides" dynamic-slides="slides">
        {{slide}}
    </ion-slide>
</ion-slide-box>

Javascript:

module.directive('dynamicHeight', function() {
    return {
        require: ['ionSlideBox'],
        link: function(scope, elem, attrs, slider) {
            scope.$watch(function() {
                return slider[0].__slider.selected();
            }, function(val) {
                var newHeight = $('.slider-slide', elem).eq(val).innerHeight();
                if (newHeight) {
                    elem.animate({
                        height: newHeight + 'px'
                    }, 500);
                }
            });
        }
    };
});

Here is my implementation

1 Like

This is brilliant. Thanks

It haven’t work for me, because the height of elm.parent was 0px.

I tried your solutions but had problems with all of them. Either height resultes in 0 or exceptions due to not found elements, or it just didn’t resize well.

Might be a problem that I use a ion-list inside 2 of 3 slides, or it interfers with another directive i use. However, I tried it myself and came up with following solution, which seems to work quite well.

Somehow, the ion-list item ignored the max-height attribute, height attribute or whatever I would give it, so I also had to apply the max-height to the inner .list of the ion-lists. The directive expects that there is exactly one root item in each slide. Didn’t work with any other solution I tried.

.directive('slideboxDynamicHeight',
     ['$timeout', '$ionicSlideBoxDelegate', '$ionicScrollDelegate',
        function ($timeout, $ionicSlideBoxDelegate, $ionicScrollDelegate) {
           return {
              require: "^ionSlideBox",
              restrict: 'A',
              link: function (scope, element, attrs, parent) {

                 var slider = angular.element(element);
                 var ionicSlideBoxDelegate = $ionicSlideBoxDelegate;

                 var slideHandle = slider.attr('delegate-handle');
                 if (slideHandle) {
                    ionicSlideBoxDelegate = ionicSlideBoxDelegate.$getByHandle(slideHandle);
                 }

                 var slideChanged = function () {
                    var maxHeight = 'none'; 
                    var slideContents = angular.element(slider[0].querySelectorAll("ion-slide > *, ion-slide > * > .list"));
                    var slides = angular.element(slider[0].querySelectorAll("ion-slide > *"));
                    slideContents.css('max-height', maxHeight); // reset slides to make them get their natural height

                    //$ionicScrollDelegate.scrollTop();
                    var currSlide = ionicSlideBoxDelegate.currentIndex() || 0;
                    maxHeight = slides[currSlide].getBoundingClientRect().height + 20 + 'px'; // add some extra spacing to avoid scrollbar issues
                    slideContents.css('max-height', maxHeight);

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

                 scope.$on('slideBox.slideChanged', slideChanged);
                 $timeout(slideChanged, 50);
              }
           };
        }]);

The topic is quite old but since its quite high on google when you search for such solution, I thought I could share my snipped also here.