File

projects/storefrontlib/shared/components/carousel/carousel.component.ts

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

OnInit

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector cx-carousel
templateUrl ./carousel.component.html

Index

Properties
Methods
Inputs
Accessors

Constructor

constructor(el: ElementRef, service: CarouselService)
Parameters :
Name Type Optional
el ElementRef No
service CarouselService No

Inputs

hideIndicators
Type : boolean
Default value : false

Indicates whether the visual indicators are used.

indicatorIcon
Type : any
Default value : ICON_TYPE.CIRCLE
items
Type : []
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)
Parameters :
Name Type Optional
size number No
currentIndex number No
Returns : number
ngOnInit
ngOnInit()
Returns : void

Properties

activeSlide
Type : 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
Returns : void
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
Component
Html element with directive

result-matching ""

    No results matching ""