File

src/app/modules/shared/components/slick/slick.component.ts

Implements

OnInit

Metadata

Index

Properties
Methods
Inputs
Outputs

Constructor

constructor()

Inputs

loadStatus
Type : string
Default value : 'none'
onHover
Type : boolean
Default value : false
viewType
Type : string
Default value : 'arrow'

Outputs

loadNext
Type : EventEmitter

Methods

computeDotSlide
computeDotSlide(index)
Parameters :
Name Optional
index No
Returns : void
ngOnChanges
ngOnChanges()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
showNext
showNext()
Returns : void
showPrev
showPrev()
Returns : void
Private updateNavigationBtnStatus
updateNavigationBtnStatus(elem: HTMLElement)
Parameters :
Name Type Optional
elem HTMLElement No
Returns : void

Properties

dotViewCount
Type : number
enableNext
Default value : false
enablePrev
Default value : false
horizontalScrollElem
Type : ElementRef | null
Default value : null
Decorators :
@ViewChild('horizontalScrollElem', {static: true})
Private scrollObserver
Type : Subscription | null
Default value : null
selectedDot
Type : number
Default value : 0
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { Subscription, fromEvent, timer } from 'rxjs';
import { debounceTime, throttleTime } from 'rxjs/operators';

@Component({
  selector: 'app-slick',
  templateUrl: './slick.component.html',
  styleUrls: ['./slick.component.scss']
})
export class SlickComponent implements OnInit {

  @Input() loadStatus = 'none';
  @Input() onHover = false;
  @Input() viewType = 'arrow';
  @Output() loadNext = new EventEmitter();
  @ViewChild('horizontalScrollElem', { static: true })
  horizontalScrollElem: ElementRef | null = null;

  enablePrev = false;
  enableNext = false;
  private scrollObserver: Subscription | null = null;
  dotViewCount: number;
  selectedDot: number = 0;

  constructor() { }

  ngOnInit() {
    if (this.horizontalScrollElem) {
      const horizontalScrollElem = this.horizontalScrollElem;
      this.scrollObserver = fromEvent(
        horizontalScrollElem.nativeElement,
        'scroll'
      )
        .pipe(debounceTime(100), throttleTime(100))
        .subscribe((_) => {
          this.updateNavigationBtnStatus(
            horizontalScrollElem.nativeElement as HTMLElement
          );
        });
    }
    const scroller = document.getElementById('ngxScroller');
    scroller.onmouseover = () => {
      scroller.style.overflowX = 'hidden'
    };
  }

  ngOnChanges() {
    timer(100).subscribe(() => {
      if (this.horizontalScrollElem) {
        this.updateNavigationBtnStatus(
          this.horizontalScrollElem?.nativeElement as HTMLElement
        );
      }
    });
  }

  ngOnDestroy() {
    if (this.scrollObserver) {
      this.scrollObserver?.unsubscribe();
    }
  }

  showPrev() {
    if (this.horizontalScrollElem) {
      if (this.horizontalScrollElem) {
        const clientWidth = this.horizontalScrollElem?.nativeElement?.clientWidth;
        this.horizontalScrollElem?.nativeElement?.scrollTo({
          left:
            this.horizontalScrollElem?.nativeElement?.scrollLeft - clientWidth,
          behavior: 'smooth',
        });
      }
    }
  }

  showNext() {
    if (this.horizontalScrollElem) {
      if (this.horizontalScrollElem) {
        const clientWidth = this.horizontalScrollElem?.nativeElement?.clientWidth;
        this.horizontalScrollElem?.nativeElement?.scrollTo({
          left:
            this.horizontalScrollElem?.nativeElement?.scrollLeft + clientWidth,
          behavior: 'smooth',
        });
      }
    }
  }

  private updateNavigationBtnStatus(elem: HTMLElement) {
    this.enablePrev = true;
    this.enableNext = true;
    if (elem.scrollLeft === 0) {
      this.enablePrev = false;
    }
    this.dotViewCount = Math.ceil(elem.scrollWidth / elem.clientWidth);
    if (elem.scrollWidth === elem.clientWidth + elem.scrollLeft) {
      if (this.loadStatus === 'hasMore') {
        this.loadNext.emit(elem);
      } else if ((elem.scrollWidth - (elem.clientWidth + elem.scrollLeft)) < 1) {
        this.enableNext = false;
      } else {
        this.enableNext = false;
      }
    }
    if ((elem.scrollWidth - (elem.clientWidth + elem.scrollLeft)) < 1) {
      this.enableNext = false;
    }
  }

  computeDotSlide(index) {
    this.selectedDot = index;
    const clientWidth = this.horizontalScrollElem?.nativeElement?.clientWidth;
    this.horizontalScrollElem?.nativeElement?.scrollTo({
      left: (index) * clientWidth,
      behavior: 'smooth',
    });
  }

}
<section class="horizontal-scroll-container h-full">
  <button *ngIf="enablePrev && viewType == 'arrow'" i18n-aria-label aria-label="back" name="content-backward-button" mat-mini-fab color="primary" (click)="showPrev()"
    class="prevBtn hidden-touch mat-slick-button" [hidden]="!enablePrev" [ngClass]="{'prevBtnHover': onHover}">
    <mat-icon>keyboard_arrow_left</mat-icon>
  </button>
  <div id="ngxScroller" name="horizontal-scroll-content-strip" class="horizontal-scroll-content" #horizontalScrollElem>
    <ng-content></ng-content>
  </div>
  <button *ngIf="enableNext && viewType == 'arrow'"  i18n-aria-label aria-label="next" name="content-forward-button" mat-mini-fab (click)="showNext()" color="primary"
    class="nextBtn hidden-touch mat-slick-button" [ngClass]="{'nextBtnHover': onHover}"
    [hidden]="!enableNext || loadStatus === 'fetching'">
    <mat-icon>keyboard_arrow_right</mat-icon>
  </button>
  <div class="nextLoading" *ngIf="loadStatus === 'fetching'">
    <mat-spinner></mat-spinner>
  </div>
</section>
<div class="pagination" *ngIf="viewType == 'dots'">
  <ng-container *ngFor="let dot of [].constructor(dotViewCount); first as isFirst; index as i">
    <span [ngClass]="(selectedDot == i) ? 'active': ''" class="slickDots" (click)="computeDotSlide(i)"></span>
  </ng-container>
</div>

./slick.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;

/* Dots Styles */
.horizontal-scroll-container {
	position: relative;
	min-height: 7rem;
}
.mat-slick-button {
	background-color: var(--white);
	color: var(--black);position: absolute;
	top: 50%;transform: translateY(-50%);z-index: 999;
	border-radius:50%;    display: flex;
    align-items: center;
    justify-content: center;color: var(--tertiary-color);
	box-shadow: var(--sbt-box-shadow-6px);
	border: 0.0625rem solid var(--sbt-body-bg);
	&:hover {
		box-shadow: none;
	}
}
.prevBtn {
	left: -1rem;
}
.nextBtn {
	right:-1rem;
}
.nextLoading {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 999;
	padding: 0;
	right: -1rem;
}
.horizontal-scroll-content {
	overflow-y: auto;
	white-space: nowrap;
	-webkit-overflow-scrolling: touch;
	height: 100%;
	flex-wrap: nowrap;
	display: flex;
	align-items: stretch;    padding-bottom: 1rem;
	-ms-overflow-style: none;
	&::-webkit-scrollbar {
		width: 0px;
		height: 0px;
	}
}
.pagination {
	display: flex;
	justify-content: center;
	align-items: center;
	padding: 0.5rem;
	.slickDots {
		display: inline-block;
		position: relative;
		cursor: pointer;
		&:before {
			content: '';
			position: absolute;
			border-radius: 50%;
			background-color:var(--gray-800);
		}
	}
	.slickDots.active {
		&:before {
			content: '';
			position: absolute;
			border-radius: 50%;
			width: 0.75rem;
			height: 0.75rem;
			background-color:var(--gray-300);
		}
	}
}



::ng-deep {
	app-slick  {
		.sb--card {
		  width: 20rem !important;
		}
	  }

	  .mat-mini-fab .mat-button-wrapper {
		width: 2.5rem;
		height: 2.5rem;
		display: flex !important;
		line-height: inherit !important;    align-items: center;
		justify-content: center;
		.mat-icon {
			font-size: 2rem;
			display: flex;
			align-items: center;
			justify-content: center;
			font-weight: bold;
		}
	}

}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""