Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit b5f220f

Browse files
ayakovlevghwesleycho
authored andcommitted
fix(carousel): respect the order of the slides
index parameter is added to the slide directive. It is used to order the slides. Fixes #488
1 parent d253208 commit b5f220f

File tree

3 files changed

+106
-11
lines changed

3 files changed

+106
-11
lines changed

src/carousel/carousel.js

+35-10
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
1717
var destroyed = false;
1818
/* direction: "prev" or "next" */
1919
self.select = $scope.select = function(nextSlide, direction) {
20-
var nextIndex = slides.indexOf(nextSlide);
20+
var nextIndex = self.indexOfSlide(nextSlide);
2121
//Decide direction if it's not given
2222
if (direction === undefined) {
23-
direction = nextIndex > currentIndex ? 'next' : 'prev';
23+
direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev';
2424
}
2525
if (nextSlide && nextSlide !== self.currentSlide) {
2626
goNext();
@@ -31,7 +31,6 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
3131

3232
angular.extend(nextSlide, {direction: direction, active: true});
3333
angular.extend(self.currentSlide || {}, {direction: direction, active: false});
34-
3534
if ($animate.enabled() && !$scope.noTransition && nextSlide.$element) {
3635
$scope.$currentTransition = true;
3736
// TODO: Switch to use .one when upgrading beyond 1.2.21
@@ -52,26 +51,45 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
5251
destroyed = true;
5352
});
5453

54+
function getSlideByIndex(index) {
55+
if (angular.isUndefined(slides[index].index)) {
56+
return slides[index];
57+
}
58+
var i, len = slides.length;
59+
for (i = 0; i < slides.length; ++i) {
60+
if (slides[i].index == index) {
61+
return slides[i];
62+
}
63+
}
64+
}
65+
66+
self.getCurrentIndex = function() {
67+
if (self.currentSlide && angular.isDefined(self.currentSlide.index)) {
68+
return +self.currentSlide.index;
69+
}
70+
return currentIndex;
71+
};
72+
5573
/* Allow outside people to call indexOf on slides array */
5674
self.indexOfSlide = function(slide) {
57-
return slides.indexOf(slide);
75+
return angular.isDefined(slide.index) ? +slide.index : slides.indexOf(slide);
5876
};
5977

6078
$scope.next = function() {
61-
var newIndex = (currentIndex + 1) % slides.length;
79+
var newIndex = (self.getCurrentIndex() + 1) % slides.length;
6280

6381
//Prevent this user-triggered transition from occurring if there is already one in progress
6482
if (!$scope.$currentTransition) {
65-
return self.select(slides[newIndex], 'next');
83+
return self.select(getSlideByIndex(newIndex), 'next');
6684
}
6785
};
6886

6987
$scope.prev = function() {
70-
var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1;
88+
var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1;
7189

7290
//Prevent this user-triggered transition from occurring if there is already one in progress
7391
if (!$scope.$currentTransition) {
74-
return self.select(slides[newIndex], 'prev');
92+
return self.select(getSlideByIndex(newIndex), 'prev');
7593
}
7694
};
7795

@@ -134,6 +152,11 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
134152
};
135153

136154
self.removeSlide = function(slide) {
155+
if (angular.isDefined(slide.index)) {
156+
slides.sort(function(a, b) {
157+
return +a.index > +b.index;
158+
});
159+
}
137160
//get the index of the slide inside the carousel
138161
var index = slides.indexOf(slide);
139162
slides.splice(index, 1);
@@ -213,13 +236,14 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition'])
213236
* Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element.
214237
*
215238
* @param {boolean=} active Model binding, whether or not this slide is currently active.
239+
* @param {number=} index The index of the slide. The slides will be sorted by this parameter.
216240
*
217241
* @example
218242
<example module="ui.bootstrap">
219243
<file name="index.html">
220244
<div ng-controller="CarouselDemoCtrl">
221245
<carousel>
222-
<slide ng-repeat="slide in slides" active="slide.active">
246+
<slide ng-repeat="slide in slides" active="slide.active" index="$index">
223247
<img ng-src="{{slide.image}}" style="margin:auto;">
224248
<div class="carousel-caption">
225249
<h4>Slide {{$index}}</h4>
@@ -253,7 +277,8 @@ function CarouselDemoCtrl($scope) {
253277
replace: true,
254278
templateUrl: 'template/carousel/slide.html',
255279
scope: {
256-
active: '=?'
280+
active: '=?',
281+
index: '=?'
257282
},
258283
link: function (scope, element, attrs, carouselCtrl) {
259284
carouselCtrl.addSlide(scope, element);

src/carousel/test/carousel.spec.js

+70
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,76 @@ describe('carousel', function() {
267267
expect($interval.cancel).toHaveBeenCalled();
268268
});
269269

270+
describe('slide order', function() {
271+
272+
beforeEach(function() {
273+
scope.slides = [
274+
{active:false,content:'one', id:1},
275+
{active:false,content:'two', id:2},
276+
{active:false,content:'three', id:3}
277+
];
278+
elm = $compile(
279+
'<carousel interval="interval" no-transition="true" no-pause="nopause">' +
280+
'<slide ng-repeat="slide in slides | orderBy: \'id\' " active="slide.active" index="$index">' +
281+
'{{slide.content}}' +
282+
'</slide>' +
283+
'</carousel>'
284+
)(scope);
285+
scope.$apply();
286+
scope.slides[0].id = 3;
287+
scope.slides[1].id = 1;
288+
scope.slides[2].id = 2;
289+
scope.$apply();
290+
});
291+
292+
it('should change dom when an order of the slides was changed', function() {
293+
testSlideActive(0);
294+
var contents = elm.find('div.item');
295+
expect(contents.length).toBe(3);
296+
expect(contents.eq(0).text()).toBe('two');
297+
expect(contents.eq(1).text()).toBe('three');
298+
expect(contents.eq(2).text()).toBe('one');
299+
});
300+
301+
it('should select next after order change', function() {
302+
testSlideActive(0);
303+
var next = elm.find('a.right');
304+
next.click();
305+
testSlideActive(1);
306+
});
307+
308+
it('should select prev after order change', function() {
309+
testSlideActive(0);
310+
var prev = elm.find('a.left');
311+
prev.click();
312+
testSlideActive(2);
313+
});
314+
315+
it('should add slide in the specified position', function() {
316+
testSlideActive(0);
317+
scope.slides[2].id = 4;
318+
scope.slides.push({active:false,content:'four', id:2});
319+
scope.$apply();
320+
var contents = elm.find('div.item');
321+
expect(contents.length).toBe(4);
322+
expect(contents.eq(0).text()).toBe('two');
323+
expect(contents.eq(1).text()).toBe('four');
324+
expect(contents.eq(2).text()).toBe('one');
325+
expect(contents.eq(3).text()).toBe('three');
326+
});
327+
328+
it('should remove slide after order change', function() {
329+
testSlideActive(0);
330+
scope.slides.splice(1, 1);
331+
scope.$apply();
332+
var contents = elm.find('div.item');
333+
expect(contents.length).toBe(2);
334+
expect(contents.eq(0).text()).toBe('three');
335+
expect(contents.eq(1).text()).toBe('one');
336+
});
337+
338+
});
339+
270340
});
271341

272342
describe('controller', function() {

template/carousel/carousel.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div ng-mouseenter="pause()" ng-mouseleave="play()" class="carousel" ng-swipe-right="prev()" ng-swipe-left="next()">
22
<ol class="carousel-indicators" ng-show="slides.length > 1">
3-
<li ng-repeat="slide in slides track by $index" ng-class="{active: isActive(slide)}" ng-click="select(slide)"></li>
3+
<li ng-repeat="slide in slides | orderBy:'index' track by $index" ng-class="{active: isActive(slide)}" ng-click="select(slide)"></li>
44
</ol>
55
<div class="carousel-inner" ng-transclude></div>
66
<a class="left carousel-control" ng-click="prev()" ng-show="slides.length > 1"><span class="glyphicon glyphicon-chevron-left"></span></a>

0 commit comments

Comments
 (0)