File
Description
Generic carousel component that can be used to render any carousel items,
such as products, images, banners, or any component. Carousel items are
rendered in so-called carousel slides, and the previous/next buttons as well as
the indicator-buttons can used to navigate the slides.
The component uses an array of Observables (items$) as an input, to allow
for lazy loading of items.
The number of items per slide is calculated with the itemWidth, which can given
in pixels or percentage.
To allow for flexible rendering of items, the rendering is delegated to the
given template. This allows for maximum flexibility.
Implements
Metadata
| changeDetection |
ChangeDetectionStrategy.OnPush |
| selector |
cx-carousel |
| templateUrl |
./carousel.component.html |
Index
Properties
|
|
|
Methods
|
|
|
Inputs
|
|
|
Accessors
|
|
|
|
hideIndicators
|
Type : boolean
|
Default value : false
|
|
|
Indicates whether the visual indicators are used.
|
|
indicatorIcon
|
Type : any
|
Default value : ICON_TYPE.CIRCLE
|
|
|
|
itemWidth
|
Type : string
|
Default value : '300px'
|
|
|
Specifies the minimum size of the carousel item, either in px or %.
This value is used for the calculation of numbers per carousel, so that
the number of carousel items is dynamic. The calculation uses the itemWidth
and the host element clientWidth, so that the carousel is reusable in
different layouts (for example in a 50% grid).
|
|
nextIcon
|
Type : any
|
Default value : ICON_TYPE.CARET_RIGHT
|
|
|
|
previousIcon
|
Type : any
|
Default value : ICON_TYPE.CARET_LEFT
|
|
|
|
template
|
Type : TemplateRef<any>
|
|
|
The template is rendered for each item, so that the actual
view can be given by the compoent that uses the CarouselComponent.
|
|
title
|
Type : string
|
|
|
The title is rendered as the carousel heading.
|
Methods
|
getSlideNumber
|
getSlideNumber(size: number, currentIndex: number)
|
|
|
|
|
|
hideIndicators
|
Default value : false
|
Decorators :
@Input()
|
|
|
Indicates whether the visual indicators are used.
|
|
indicatorIcon
|
Default value : ICON_TYPE.CIRCLE
|
Decorators :
@Input()
|
|
|
|
items
|
Type : Observable<any>[]
|
|
|
The items$ represent the carousel items. The items$ are
observables so that the items can be loaded on demand.
|
|
itemWidth
|
Type : string
|
Default value : '300px'
|
Decorators :
@Input()
|
|
|
Specifies the minimum size of the carousel item, either in px or %.
This value is used for the calculation of numbers per carousel, so that
the number of carousel items is dynamic. The calculation uses the itemWidth
and the host element clientWidth, so that the carousel is reusable in
different layouts (for example in a 50% grid).
|
|
nextIcon
|
Default value : ICON_TYPE.CARET_RIGHT
|
Decorators :
@Input()
|
|
|
|
previousIcon
|
Default value : ICON_TYPE.CARET_LEFT
|
Decorators :
@Input()
|
|
|
|
size$
|
Type : Observable<number>
|
|
|
|
template
|
Type : TemplateRef<any>
|
Decorators :
@Input()
|
|
|
The template is rendered for each item, so that the actual
view can be given by the compoent that uses the CarouselComponent.
|
|
title
|
Type : string
|
Decorators :
@Input()
|
|
|
The title is rendered as the carousel heading.
|
Accessors
|
setItems
|
setsetItems(inputItems: Observable[])
|
|
|
Parameters :
| Name |
Type |
Optional |
| inputItems |
Observable<any>[]
|
No
|
|
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
isDevMode,
OnInit,
TemplateRef,
} from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { ICON_TYPE } from '../../../cms-components/misc/icon/icon.model';
import { CarouselService } from './carousel.service';
/**
* Generic carousel component that can be used to render any carousel items,
* such as products, images, banners, or any component. Carousel items are
* rendered in so-called carousel slides, and the previous/next buttons as well as
* the indicator-buttons can used to navigate the slides.
*
* The component uses an array of Observables (`items$`) as an input, to allow
* for lazy loading of items.
*
* The number of items per slide is calculated with the `itemWidth`, which can given
* in pixels or percentage.
*
* To allow for flexible rendering of items, the rendering is delegated to the
* given `template`. This allows for maximum flexibility.
*/
@Component({
selector: 'cx-carousel',
templateUrl: './carousel.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CarouselComponent implements OnInit {
/**
* The title is rendered as the carousel heading.
*/
@Input() title: string;
/**
* The items$ represent the carousel items. The items$ are
* observables so that the items can be loaded on demand.
*/
items: Observable<any>[];
@Input('items')
set setItems(inputItems: Observable<any>[]) {
this.items = inputItems;
//Reset slider when changing products
this.activeSlide = 0;
}
/**
* The template is rendered for each item, so that the actual
* view can be given by the compoent that uses the `CarouselComponent`.
*/
@Input() template: TemplateRef<any>;
/**
* Specifies the minimum size of the carousel item, either in px or %.
* This value is used for the calculation of numbers per carousel, so that
* the number of carousel items is dynamic. The calculation uses the `itemWidth`
* and the host element `clientWidth`, so that the carousel is reusable in
* different layouts (for example in a 50% grid).
*/
@Input() itemWidth = '300px';
/**
* Indicates whether the visual indicators are used.
*/
@Input() hideIndicators = false;
@Input() indicatorIcon = ICON_TYPE.CIRCLE;
@Input() previousIcon = ICON_TYPE.CARET_LEFT;
@Input() nextIcon = ICON_TYPE.CARET_RIGHT;
activeSlide: number;
size$: Observable<number>;
constructor(protected el: ElementRef, protected service: CarouselService) {}
ngOnInit() {
if (!this.template && isDevMode()) {
console.error(
'No template reference provided to render the carousel items for the `cx-carousel`'
);
return;
}
this.size$ = this.service
.getItemsPerSlide(this.el.nativeElement, this.itemWidth)
.pipe(tap(() => (this.activeSlide = 0)));
}
getSlideNumber(size: number, currentIndex: number): number {
let normalizedCurrentIndex = currentIndex + 1;
return Math.ceil(normalizedCurrentIndex / size);
}
}
<ng-container *ngIf="items?.length > 0 && (size$ | async) as size">
<h2 *ngIf="title">{{ title }}</h2>
<div class="carousel-panel" [ngClass]="'size-' + size">
<button
*ngIf="size < items.length"
class="previous"
(click)="activeSlide = activeSlide - size"
[disabled]="activeSlide === 0"
[attr.aria-label]="'carousel.previousSlide' | cxTranslate"
>
<cx-icon [type]="previousIcon"></cx-icon>
</button>
<div class="slides">
<ng-container *ngFor="let _ of items; let i = index">
<div
class="slide"
*ngIf="i % size === 0"
[class.active]="i === activeSlide"
>
<ng-container
*ngFor="let item of items | slice: i:i + size; let j = index"
>
<div
*ngIf="item | async as data"
class="item"
[class.active]="i === activeSlide"
>
<ng-container
*ngTemplateOutlet="template; context: { item: data }"
></ng-container>
</div>
</ng-container>
</div>
</ng-container>
</div>
<button
*ngIf="size < items.length"
class="next"
(click)="activeSlide = activeSlide + size"
tabindex="-1"
[disabled]="activeSlide > items.length - size - 1"
[attr.aria-label]="'carousel.nextSlide' | cxTranslate"
>
<cx-icon [type]="nextIcon"></cx-icon>
</button>
</div>
<div *ngIf="!hideIndicators && size < items.length" class="indicators">
<ng-container *ngFor="let _ of items; let i = index">
<button
*ngIf="i % size === 0"
(focus)="activeSlide = i"
[disabled]="i === activeSlide"
[attr.aria-label]="
'carousel.slideNumber'
| cxTranslate: { currentSlideNumber: getSlideNumber(size, i) }
"
tabindex="-1"
>
<cx-icon [type]="indicatorIcon" aria-hidden="true"></cx-icon>
</button>
</ng-container>
</div>
</ng-container>
Legend
Html element with directive