Skip to content

Commit e3103f0

Browse files
feat(module: carousel): nzLoop to prevent the carousel to go in a loop (#7693)
* feat(module: carousel): `nzLoop` to prevent the carousel to go in a loop * ci(module: carousel): improve test coverage
1 parent bec3b42 commit e3103f0

File tree

8 files changed

+102
-2
lines changed

8 files changed

+102
-2
lines changed

components/carousel/carousel.component.ts

+13-2
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
127127
@Input() @WithConfig() @InputBoolean() nzAutoPlay: boolean = false;
128128
@Input() @WithConfig() @InputNumber() nzAutoPlaySpeed: number = 3000;
129129
@Input() @InputNumber() nzTransitionSpeed = 500;
130+
@Input() @WithConfig() nzLoop: boolean = true;
130131

131132
/**
132133
* this property is passed directly to an NzCarouselBaseStrategy
@@ -300,7 +301,12 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
300301
}
301302

302303
goTo(index: number): void {
303-
if (this.carouselContents && this.carouselContents.length && !this.isTransiting) {
304+
if (
305+
this.carouselContents &&
306+
this.carouselContents.length &&
307+
!this.isTransiting &&
308+
(this.nzLoop || (index >= 0 && index < this.carouselContents.length))
309+
) {
304310
const length = this.carouselContents.length;
305311
const from = this.activeIndex;
306312
const to = (index + length) % length;
@@ -386,7 +392,12 @@ export class NzCarouselComponent implements AfterContentInit, AfterViewInit, OnD
386392
const xDelta = this.pointerDelta ? this.pointerDelta.x : 0;
387393

388394
// Switch to another slide if delta is bigger than third of the width.
389-
if (Math.abs(xDelta) > this.gestureRect!.width / 3) {
395+
if (
396+
Math.abs(xDelta) > this.gestureRect!.width / 3 &&
397+
(this.nzLoop ||
398+
(xDelta <= 0 && this.activeIndex + 1 < this.carouselContents.length) ||
399+
(xDelta > 0 && this.activeIndex > 0))
400+
) {
390401
this.goTo(xDelta > 0 ? this.activeIndex - 1 : this.activeIndex + 1);
391402
} else {
392403
this.goTo(this.activeIndex);

components/carousel/carousel.spec.ts

+31
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,35 @@ describe('carousel', () => {
220220
tickMilliseconds(fixture, 700);
221221
expect(carouselContents[1].nativeElement.classList).toContain('slick-active');
222222
}));
223+
224+
it('should disable loop work', fakeAsync(() => {
225+
testComponent.loop = false;
226+
fixture.detectChanges();
227+
swipe(testComponent.nzCarouselComponent, -10);
228+
tickMilliseconds(fixture, 700);
229+
expect(carouselContents[0].nativeElement.classList).toContain('slick-active');
230+
swipe(testComponent.nzCarouselComponent, -1000);
231+
tickMilliseconds(fixture, 700);
232+
expect(carouselContents[0].nativeElement.classList).toContain('slick-active');
233+
234+
testComponent.loop = true;
235+
fixture.detectChanges();
236+
swipe(testComponent.nzCarouselComponent, -1000);
237+
tickMilliseconds(fixture, 700);
238+
expect(carouselContents[3].nativeElement.classList).toContain('slick-active');
239+
swipe(testComponent.nzCarouselComponent, 1000);
240+
tickMilliseconds(fixture, 700);
241+
expect(carouselContents[0].nativeElement.classList).toContain('slick-active');
242+
243+
testComponent.loop = false;
244+
testComponent.autoPlay = true;
245+
testComponent.autoPlaySpeed = 1000;
246+
fixture.detectChanges();
247+
tick(10000);
248+
expect(carouselContents[3].nativeElement.classList).toContain('slick-active');
249+
tick(1000 + 10);
250+
expect(carouselContents[3].nativeElement.classList).toContain('slick-active');
251+
}));
223252
});
224253

225254
describe('strategies', () => {
@@ -406,6 +435,7 @@ function swipe(carousel: NzCarouselComponent, distance: number): void {
406435
[nzDotRender]="dotRender"
407436
[nzAutoPlay]="autoPlay"
408437
[nzAutoPlaySpeed]="autoPlaySpeed"
438+
[nzLoop]="loop"
409439
(nzAfterChange)="afterChange($event)"
410440
(nzBeforeChange)="beforeChange($event)"
411441
>
@@ -426,6 +456,7 @@ export class NzTestCarouselBasicComponent {
426456
array = [1, 2, 3, 4];
427457
autoPlay = false;
428458
autoPlaySpeed = 3000;
459+
loop = true;
429460
afterChange = jasmine.createSpy('afterChange callback');
430461
beforeChange = jasmine.createSpy('beforeChange callback');
431462
}

components/carousel/demo/loop.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
order: 5
3+
title:
4+
zh-CN: 循环
5+
en-US: Loop
6+
---
7+
8+
## zh-CN
9+
10+
防止轮播进入循环
11+
12+
## en-US
13+
14+
Prevent the carousel to go in a loop

components/carousel/demo/loop.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Component } from '@angular/core';
2+
3+
@Component({
4+
selector: 'nz-demo-carousel-loop',
5+
template: `
6+
<nz-carousel nzAutoPlay [nzEffect]="effect" [nzLoop]="false">
7+
<div nz-carousel-content *ngFor="let index of array">
8+
<h3>{{ index }}</h3>
9+
</div>
10+
</nz-carousel>
11+
`,
12+
styles: [
13+
`
14+
[nz-carousel-content] {
15+
text-align: center;
16+
height: 160px;
17+
line-height: 160px;
18+
background: #364d79;
19+
color: #fff;
20+
overflow: hidden;
21+
}
22+
23+
h3 {
24+
color: #fff;
25+
margin-bottom: 0;
26+
user-select: none;
27+
}
28+
`
29+
]
30+
})
31+
export class NzDemoCarouselLoopComponent {
32+
array = [1, 2, 3, 4];
33+
effect = 'scrollx';
34+
}

components/carousel/doc/index.en-US.md

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { NzCarouselModule } from 'ng-zorro-antd/carousel';
3030
| `[nzDots]` | Whether to show the dots at the bottom of the gallery | `boolean` | `true` ||
3131
| `[nzEffect]` | Transition effect | `'scrollx'\|'fade'` | `'scrollx'` ||
3232
| `[nzEnableSwipe]` | Whether to support swipe gesture | `boolean` | `true` ||
33+
| `[nzLoop]` | Whether to enable the carousel to go in a loop | `boolean` | `true` ||
3334
| `(nzAfterChange)` | Callback function called after the current index changes | `EventEmitter<number>` | - |
3435
| `(nzBeforeChange)` | Callback function called before the current index changes | `EventEmitter{ from: number; to: number }>` | - |
3536

components/carousel/doc/index.zh-CN.md

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { NzCarouselModule } from 'ng-zorro-antd/carousel';
3131
| `[nzDots]` | 是否显示面板指示点 | `boolean` | `true` ||
3232
| `[nzEffect]` | 动画效果函数,可取 `scrollx`, `fade` | `'scrollx'\|'fade'`|`'scrollx'` ||
3333
| `[nzEnableSwipe]` | 是否支持手势划动切换 | `boolean` | `true` ||
34+
| `[nzLoop]` | 是否支持循环 | `boolean` | `true` ||
3435
| `(nzAfterChange)` | 切换面板的回调 | `EventEmitter<number>` | - |
3536
| `(nzBeforeChange)` | 切换面板的回调 | `EventEmitter<{ from: number; to: number }>` | - |
3637

components/core/config/config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ export interface CarouselConfig {
160160
nzEffect?: 'scrollx' | 'fade' | string;
161161
nzEnableSwipe?: boolean;
162162
nzVertical?: boolean;
163+
nzLoop?: boolean;
163164
}
164165

165166
export interface CascaderConfig {
+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { pxToNumber } from './text-measure';
2+
3+
describe('pxToNumber', () => {
4+
it('should return 0 when value is null', () => {
5+
expect(pxToNumber(null)).toBe(0);
6+
});
7+
});

0 commit comments

Comments
 (0)