File

src/third-party-components/carousel-component/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 OnDestroy OnChanges

Metadata

Index

Properties
Methods
Inputs
Accessors

Constructor

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

Inputs

autocycleInterval
Type : number
Default value : 5000
autocycleOn
Type : boolean
Default value : true

Autocycle configuration Autocycle on is default, interval 5000ms

hideIndicators
Type : boolean
Default value : false

Indicates whether the visual indicators are used.

hideNavigation
Type : boolean
Default value : false
indicatorIcon
Type : any
Default value : ICON_TYPE.CIRCLE
items
Type : Array<Observable<any>>
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

Navigation configuration

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

autocycle
autocycle()
Returns : void
nextSlide
nextSlide()
Returns : void
ngOnChanges
ngOnChanges()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
previousSlide
previousSlide()
Returns : void

Properties

activeSlide
Type : number
autocycleIntervalId
Type : any
items
Type : Array<Observable<any>>

The items$ represent the carousel items. The items$ are observables so that the items can be loaded on demand.

size
Type : number
Default value : 0
size$
Type : Observable<number>

Accessors

setItems
setsetItems(inputItems: Array>)
Parameters :
Name Type Optional
inputItems Array<Observable<any>> No
Returns : void
import {
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  Input,
  isDevMode,
  OnInit,
  TemplateRef,
  OnDestroy,
  ChangeDetectorRef,
  OnChanges,
} from '@angular/core';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { ICON_TYPE } from '@spartacus/storefront';
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,
    standalone: false
})
export class CarouselComponent implements OnInit, OnDestroy, OnChanges {
  /**
   * 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: Array<Observable<any>>;
  // eslint-disable-next-line @angular-eslint/no-input-rename
  @Input('items')
  set setItems(inputItems: Array<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;

  /**
   * Navigation configuration
   */
  @Input() previousIcon = ICON_TYPE.CARET_LEFT;
  @Input() nextIcon = ICON_TYPE.CARET_RIGHT;
  @Input() hideNavigation = false;

  /**
   * Autocycle configuration
   * Autocycle on is default, interval 5000ms
   */

  @Input() autocycleOn = true;
  @Input() autocycleInterval = 5000;

  activeSlide: number;
  size$: Observable<number>;

  autocycleIntervalId: any; // variable to clear autocycle interval
  size = 0;

  constructor(protected el: ElementRef, protected service: CarouselService, private changeDetectorRef: ChangeDetectorRef) {}

  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((calculatedSize: number) => {
        this.activeSlide = 0;
        this.size = calculatedSize;
      })
    );
  }

  ngOnChanges() {
    clearInterval(this.autocycleIntervalId);
    if (this.autocycleOn === true) {
      this.autocycle();
    }
  }

  nextSlide() {
    if (this.activeSlide < this.items.length - 1) {
      this.activeSlide += this.size;
    } else this.activeSlide = 0;
  }

  previousSlide() {
    if (this.activeSlide > 0) {
      this.activeSlide -= this.size;
    } else this.activeSlide = this.items.length - 1;
  }

  autocycle() {
    this.autocycleIntervalId = setInterval(() => {
      this.nextSlide();
      this.changeDetectorRef.detectChanges();
    }, this.autocycleInterval);
  }

  ngOnDestroy() {
    clearInterval(this.autocycleIntervalId);
  }
}
<!-- Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.


**************************


This file was modified:

Modifications copyright (c) 2023 Crownpeak Technology GmbH

Original source from: https://github.com/SAP/spartacus/blob/develop/projects/storefrontlib/src/shared/components/carousel/carousel.component.html (commit 58f74b8 on 19 May 2020)

Modifications:

  * moved logic for previous and next buttons to spartacusCarousel.component.ts
-->

<ng-container *ngIf="items?.length > 0 && (size$ | async) as size">
  <h3 *ngIf="title">{{ title }}</h3>

  <div class="carousel-panel" [ngClass]="'size-' + size">
    <button
      *ngIf="hideNavigation === false && size < items.length && autocycleOn === false"
      class="previous"
      (click)="previousSlide()"
      [disabled]="activeSlide === 0"
    >
      <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="hideNavigation === false && size < items.length && autocycleOn === false"
      class="next"
      (click)="nextSlide()"
      tabindex="-1"
      [disabled]="activeSlide > items.length - size - 1"
    >
      <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" tabindex="-1">
        <cx-icon [type]="indicatorIcon"></cx-icon>
      </button>
    </ng-container>
  </div>
</ng-container>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""