File
Implements
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Outputs
|
|
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)
|
|
|
ngOnChanges
|
ngOnChanges()
|
|
|
ngOnDestroy
|
ngOnDestroy()
|
|
|
Private
updateNavigationBtnStatus
|
updateNavigationBtnStatus(elem: HTMLElement)
|
|
|
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>
@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 with directive