Skip to content

Commit

Permalink
fix(slides): changed the way looped/duplicates slides work, added doc…
Browse files Browse the repository at this point in the history
…umentation

changed the way looped/duplicates slides work, added documentation

closes #6305
  • Loading branch information
danbucholtz committed May 5, 2016
2 parents f19b2fe + 302d566 commit 44d5a0f
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 128 deletions.
165 changes: 76 additions & 89 deletions js/angular/directive/slides.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,82 @@
*
* @usage
* ```html
* <ion-slides options="options" slider="data.slider">
* <ion-slide-page>
* <div class="box blue"><h1>BLUE</h1></div>
* </ion-slide-page>
* <ion-slide-page>
* <div class="box yellow"><h1>YELLOW</h1></div>
* </ion-slide-page>
* <ion-slide-page>
* <div class="box pink"><h1>PINK</h1></div>
* </ion-slide-page>
* </ion-slides>
* <ion-content scroll="false">
* <ion-slides options="options" slider="data.slider">
* <ion-slide-page>
* <div class="box blue"><h1>BLUE</h1></div>
* </ion-slide-page>
* <ion-slide-page>
* <div class="box yellow"><h1>YELLOW</h1></div>
* </ion-slide-page>
* <ion-slide-page>
* <div class="box pink"><h1>PINK</h1></div>
* </ion-slide-page>
* </ion-slides>
* </ion-content>
* ```
*
* ```js
* $scope.options = {
* loop: false,
* effect: fade,
* effect: 'fade',
* speed: 500,
* }
* $scope.data = {};
* $scope.$watch('data.slider', function(nv, ov) {
* $scope.slider = $scope.data.slider;
* })
*
* $scope.$on("$ionicSlides.sliderInitialized", function(event, data){
* // data.slider is the instance of Swiper
* $scope.slider = data.slider;
* });
*
* $scope.$on("$ionicSlides.slideChangeStart", function(event, data){
* console.log('Slide change is beginning');
* });
*
* $scope.$on("$ionicSlides.slideChangeEnd", function(event, data){
* // note: the indexes are 0-based
* $scope.activeIndex = data.activeIndex;
* $scope.previousIndex = data.previousIndex;
* });
*
* ```
*
* ## Slide Events
*
* The slides component dispatches events when the active slide changes
*
* <table class="table">
* <tr>
* <td><code>$ionicSlides.slideChangeStart</code></td>
* <td>This event is emitted when a slide change begins</td>
* </tr>
* <tr>
* <td><code>$ionicSlides.slideChangeEnd</code></td>
* <td>This event is emitted when a slide change completes</td>
* </tr>
* <tr>
* <td><code>$ionicSlides.sliderInitialized</code></td>
* <td>This event is emitted when the slider is initialized. It provides access to an instance of the slider.</td>
* </tr>
* </table>
*
*
* ## Updating Slides Dynamically
* When applying data to the slider at runtime, typically everything will work as expected.
*
* In the event that the slides are looped, use the `updateLoop` method on the slider to ensure the slides update correctly.
*
* ```
* $scope.$on("$ionicSlides.sliderInitialized", function(event, data){
* // grab an instance of the slider
* $scope.slider = data.slider;
* });
*
* function dataChangeHandler(){
* // call this function when data changes, such as an HTTP request, etc
* if ( $scope.slider ){
* $scope.slider.updateLoop();
* }
* }
* ```
*
*/
Expand All @@ -61,11 +114,6 @@ function($animate, $timeout, $compile) {
'</div>',
controller: ['$scope', '$element', function($scope, $element) {
var _this = this;
var _watchHandler = null;
var _enterHandler = null;
var _afterLeaveHandler = null;
var _modalRemovedHandler = null;
var _modalPresentedHandler = null;

this.update = function() {
$timeout(function() {
Expand Down Expand Up @@ -96,52 +144,6 @@ function($animate, $timeout, $compile) {
_this.update();
}, 50);

this.updateLoop = ionic.debounce(function() {
if ( _this._options.loop ) {
_this.__slider.updateLoop();
}
}, 50);

this.watchForChanges = function() {
if ( !_watchHandler ) {
// if we're not already watching, start watching
_watchHandler = $scope.$watch(function() {
console.log("Watch triggered");
_this.updateLoop();
});
}
};

this.stopWatching = function() {
if ( _watchHandler ) {
console.log("Stopping watching...");
_watchHandler();
_watchHandler = null;
}
};

this.cleanUpEventHandlers = function() {
if ( _enterHandler ) {
_enterHandler();
_enterHandler = null;
}

if ( _afterLeaveHandler ) {
_afterLeaveHandler();
_afterLeaveHandler = null;
}

if ( _modalRemovedHandler ) {
_modalRemovedHandler();
_modalRemovedHandler = null;
}

if ( _modalPresentedHandler ) {
_modalPresentedHandler();
_modalPresentedHandler = null;
}
};

this.getSlider = function() {
return _this.__slider;
};
Expand All @@ -160,37 +162,22 @@ function($animate, $timeout, $compile) {
$timeout(function() {
var slider = new ionic.views.Swiper($element.children()[0], newOptions, $scope, $compile);

$scope.$emit("$ionicSlides.sliderInitialized", { slider: slider });

_this.__slider = slider;
$scope.slider = _this.__slider;

$scope.$on('$destroy', function() {
slider.destroy();
_this.__slider = null;
_this.stopWatching();
_this.cleanUpEventHandlers();

});

_this.watchForChanges();

_enterHandler = $scope.$on("$ionicView.enter", function() {
_this.watchForChanges();
});

_afterLeaveHandler = $scope.$on("$ionicView.afterLeave", function() {
_this.stopWatching();
});

_modalRemovedHandler = $scope.$on("$ionic.modalRemoved", function() {
_this.stopWatching();
});

_modalPresentedHandler = $scope.$on("$ionic.modalPresented", function() {
_this.watchForChanges();
});

});

$timeout(function() {
// if it's a loop, render the slides again just incase
_this.rapidUpdate();
}, 200);

}],

link: function($scope) {
Expand Down
61 changes: 42 additions & 19 deletions js/views/slidesView.js
Original file line number Diff line number Diff line change
Expand Up @@ -1811,6 +1811,11 @@
s.emit('onTransitionStart', s);
if (s.activeIndex !== s.previousIndex) {
s.emit('onSlideChangeStart', s);
_scope.$emit("$ionicSlides.slideChangeStart", {
slider: s,
activeIndex: s.getSlideDataIndex(s.activeIndex),
previousIndex: s.getSlideDataIndex(s.previousIndex)
});
if (s.activeIndex > s.previousIndex) {
s.emit('onSlideNextStart', s);
}
Expand All @@ -1830,6 +1835,11 @@
s.emit('onTransitionEnd', s);
if (s.activeIndex !== s.previousIndex) {
s.emit('onSlideChangeEnd', s);
_scope.$emit("$ionicSlides.slideChangeEnd", {
slider: s,
activeIndex: s.getSlideDataIndex(s.activeIndex),
previousIndex: s.getSlideDataIndex(s.previousIndex)
});
if (s.activeIndex > s.previousIndex) {
s.emit('onSlideNextEnd', s);
}
Expand Down Expand Up @@ -2046,24 +2056,38 @@
};

s.updateLoop = function(){
// this is an Ionic custom function
var duplicates = s.wrapper.children('.' + s.params.slideClass + '.' + s.params.slideDuplicateClass);
var slides = s.wrapper.children('.' + s.params.slideClass);
for ( var i = 0; i < duplicates.length; i++ ){
var duplicate = duplicates[i];
var swiperSlideIndex = angular.element(duplicate).attr("data-swiper-slide-index");
// loop through each slide
for ( var j = 0; i < slides.length; j++ ){
// if it's not a duplicate, and the data swiper slide index matches the duplicate value
var slide = slides[j]
if ( !angular.element(slide).hasClass(s.params.slideDuplicateClass) && angular.element(slide).attr("data-swiper-slide-index") === swiperSlideIndex ){
// sweet, it's a match
duplicate.innerHTML = slide.innerHTML;
var currentSlide = s.slides.eq(s.activeIndex);
if ( angular.element(currentSlide).hasClass(s.params.slideDuplicateClass) ){
// we're on a duplicate, so slide to the non-duplicate
var swiperSlideIndex = angular.element(currentSlide).attr("data-swiper-slide-index");
var slides = s.wrapper.children('.' + s.params.slideClass);
for ( var i = 0; i < slides.length; i++ ){
if ( !angular.element(slides[i]).hasClass(s.params.slideDuplicateClass) && angular.element(slides[i]).attr("data-swiper-slide-index") === swiperSlideIndex ){
s.slideTo(i, 0, false, true);
break;
}
}
// if we needed to switch slides, we did that. So, now call the createLoop function internally
setTimeout(function(){
s.createLoop();
}, 50);
}
}

s.getSlideDataIndex = function(slideIndex){
// this is an Ionic custom function
// Swiper loops utilize duplicate DOM elements for slides when in a loop
// which means that we cannot rely on the actual slide index for our events
// because index 0 does not necessarily point to index 0
// and index n+1 does not necessarily point to the expected piece of data
// therefore, rather than using the actual slide index we should
// use the data index that swiper includes as an attribute on the dom elements
// because this is what will be meaningful to the consumer of our events
var slide = s.slides.eq(slideIndex);
var attributeIndex = angular.element(slide).attr("data-swiper-slide-index");
return parseInt(attributeIndex);
}

/*=========================
Loop
===========================*/
Expand Down Expand Up @@ -2092,26 +2116,25 @@
slide.attr('data-swiper-slide-index', index);
});
for (i = 0; i < appendSlides.length; i++) {
/*newNode = angular.element(appendSlides[i]).clone().addClass(s.params.slideDuplicateClass);

newNode = angular.element(appendSlides[i]).clone().addClass(s.params.slideDuplicateClass);
newNode.removeAttr('ng-transclude');
newNode.removeAttr('ng-repeat');
scope = angular.element(appendSlides[i]).scope();
newNode = $compile(newNode)(scope);
angular.element(s.wrapper).append(newNode);
*/
s.wrapper.append($(appendSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
//s.wrapper.append($(appendSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
}
for (i = prependSlides.length - 1; i >= 0; i--) {
s.wrapper.prepend($(prependSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));
//s.wrapper.prepend($(prependSlides[i].cloneNode(true)).addClass(s.params.slideDuplicateClass));

/*newNode = angular.element(prependSlides[i]).clone().addClass(s.params.slideDuplicateClass);
newNode = angular.element(prependSlides[i]).clone().addClass(s.params.slideDuplicateClass);
newNode.removeAttr('ng-transclude');
newNode.removeAttr('ng-repeat');

scope = angular.element(prependSlides[i]).scope();
newNode = $compile(newNode)(scope);
angular.element(s.wrapper).prepend(newNode);
*/
}
};
s.destroyLoop = function () {
Expand Down
Loading

0 comments on commit 44d5a0f

Please sign in to comment.