Slide-box Dynamic Height

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.