ionic-team / ionic-framework

A powerful cross-platform UI toolkit for building native-quality iOS, Android, and Progressive Web Apps with HTML, CSS, and JavaScript.
https://ionicframework.com
MIT License
51.09k stars 13.51k forks source link

bug: dynamically built slideBox with ng-repeat does not continue when flag is set #1890

Closed keithdmoore closed 10 years ago

keithdmoore commented 10 years ago
<ion-slide-box does-continue="true">
   <ion-slide ng-repeat="item in items">
      <div>stuff</div>
   </ion-slide>
</ion-slide-box>
mhartington commented 10 years ago

@keithdmoore, are you calling $ionicSlideBoxDelegate.update() in the controller?

keithdmoore commented 10 years ago

Yes, I am calling $ionicSlideBoxDelegate.update() upon receiving the items from the backend. The problem is that the options.continuous attribute has already been changed since the length was zero. Upon calling the delegate update function, the code was not resetting the options.continuous attribute.

keithdmoore commented 10 years ago

Just found another related issue when you have two static slide boxes with does-continue="true". It duplicates the slide boxes. Instead of two, there are now four. See this codepen: http://codepen.io/keithdmoore/pen/wzxqA

I think it has to do with this block of code in sliderView.js:

      //special case if two slides
      if (browser.transitions && options.continuous && slides.length < 3) {
        element.appendChild(slides[0].cloneNode(true));
        element.appendChild(element.children[1].cloneNode(true));
        slides = element.children;
      }
mhartington commented 10 years ago

Ah alright, I misunderstood the issue. @perrygovier, I'm going to pass this off to you since you worked with the does-continue and auto-play attributes.

tannerlinsley commented 9 years ago

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();
            });
        }
    };
});
keithdmoore commented 9 years ago

This looks like a good workaround. Seems like a watch on the "featured" array length with a call to $ionicSlideBoxDelegate.update() would be cleaner. I currently call the $ionicSlideBoxDelegate.update() upon receiving data from a http request. However, I have not tried it in the current beta14 version.

tannerlinsley commented 9 years ago

It would look cleaner, and you could easily do this in your controller, but this ensures the directives portability, ease of use, and in the case of nested slide boxes (I hope never) you would not have to specify the delegate name.

tannerlinsley commented 9 years ago

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);
                }
            });
        }
    };
});
severedsea commented 9 years ago

Still experiencing @keithdmoore 's issue on: (1) duplicate static slide boxes as well as... (2) does-continue="true" not working when ng-repeat starts off as empty list of array then dynamically adding slides after data was retrieved from server, even after calling $ionicSlideBoxDelegate.update().

I'm using v1.0.0-rc.3-nightly-1215

clarkbynum commented 9 years ago

@tannerlinsley - nice directive! I'm going to implement that in my current app. I did run into an issue when pushing new slides to my ng-repeat where the new slide would render below the slide-box before update was called. I don't think this would be a problem if my slide-box filled the entire view. If anyone runs into this issue I came up with a hack to make sure that each slide starts off with a width of zero before Ionic styles the slide.

    <ion-slide ng-repeat="url in urls track by $index" dynamic-slides="urls" style="width: 0px"></ion-slide>
tannerlinsley commented 9 years ago

I've re factored it since. I'll try and repost it. On Thu, May 7, 2015 at 8:24 AM sh3nan1gans notifications@github.com wrote:

@tannerlinsley https://github.com/tannerlinsley - nice directive! I'm going to implement that in my current app. I did run into an issue when pushing new slides to my ng-repeat where the new slide would render below the slide-box before update was called. I don't think this would be a problem if my slide-box filled the entire view. If anyone runs into this issue I came up with a hack to make sure that each slide starts off with a width of zero before Ionic styles the slide.

<ion-slide ng-repeat="url in urls track by $index" dynamic-slides="urls" style="width: 0px"></ion-slide>

— Reply to this email directly or view it on GitHub https://github.com/driftyco/ionic/issues/1890#issuecomment-99884681.

tannerlinsley commented 9 years ago
(function() {

    var module = angular.module('novi.utils');

    module.directive('watchSlides', function($interval, $timeout) {
        return {
            restrict: 'A',
            require: 'ionSlideBox',
            link: function(scope, el, attrs, slider) {

                var index = 0;

                var activeWatcher = scope.$watch(function getActiveSlide() {
                    index = slider.__slider.selected();
                    return [index, slider.__slider.count()];
                }, changeSize, true);

                scope.$watch(function() {
                    return _.size(scope.$eval(attrs.watchSlides));
                }, function(val) {
                    slider.__slider.update();
                });

                var interval = $interval(changeSize, 1000);

                // Cleanup
                scope.$on('$destroy', function() {
                    activeWatcher();
                    $interval.cancel(interval);
                });

                function changeSize() {

                    return;

                    if (!el[0].querySelectorAll('.slider-slide').length) {
                        return;
                    }

                    var newHeight = el[0].querySelectorAll('.slider-slide')[index].scrollHeight;
                    if (newHeight) {
                        $timeout(function() {
                            el.css({
                                height: newHeight + 'px'
                            });
                        });
                    }
                }

            }
        };
    });
})();
tannerlinsley commented 9 years ago

It's a little rough around the edges. Don't know how i feel about the interval. But it seems to work nicely.

tannerlinsley commented 9 years ago

Also the watch slides attribute may need to be deep watched or just watch the length of the array. Tweak as needed

hkalancheung commented 9 years ago

solved by putting an ng-if on slide-box http://forum.ionicframework.com/t/slidebox-does-continue-doesnt-work-on-ipad/14831/4