import { Component } from '@angular/core';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { TmdbService } from '../../services/tmdb.service';
import { OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Subject, takeUntil } from 'rxjs';
import { ITrending } from '../../interfaces/trending';
import Swiper from 'swiper';
import { RouterLink } from '@angular/router';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { swiperInitialization } from '../../swiper/swiperConfig';
import { ShowCardScoreComponent } from '../show-card-score/show-card-score.component';
@Component({
selector: 'app-trending',
imports: [
MatButtonToggleModule,
ShowCardScoreComponent,
CommonModule,
FormsModule,
RouterLink,
NgxSkeletonLoaderModule,
],
templateUrl: './trending.component.html',
styleUrl: './trending.component.css',
})
export class TrendingComponent implements OnInit, OnDestroy {
loading: boolean = false;
timeSelectedValue: string = 'day';
trendingShows: Array<ITrending> = [];
swiper: Swiper | null = null;
$unsubscribe: Subject<void> = new Subject<void>();
constructor(private tmdbService: TmdbService) {}
ngOnInit(): void {
this.getTrendingData(this.timeSelectedValue);
}
ngOnDestroy(): void {
this.$unsubscribe.next();
this.$unsubscribe.complete();
if (this.swiper) {
this.swiper.destroy(true, true);
}
}
// This method is triggered when the selection changes
onSelectionChange(event: any) {
this.timeSelectedValue = event.value;
this.getTrendingData(this.timeSelectedValue);
}
getTrendingData(timeSelectedValue: string) {
this.trendingShows = [];
this.loading = true;
if (this.swiper) {
this.swiper.destroy(true, true); // Destroy the current Swiper instance
}
this.swiper = swiperInitialization('#swiperTrending', {
300: { slidesPerView: 1 },
500: { slidesPerView: 2 },
900: { slidesPerView: 4 },
1200: { slidesPerView: 5 },
1400: { slidesPerView: 6 },
1800: { slidesPerView: 8 },
});
this.tmdbService
.getTrendingAll(timeSelectedValue)
.pipe(takeUntil(this.$unsubscribe))
.subscribe((data) => {
console.log(data);
// Process data here
data.results.map((show: any) => {
if (show.name !== undefined) show['title'] = show.name;
this.trendingShows.push(show);
});
this.loading = false;
});
}
}
<div class="container-fluid mb-3">
<div class="trendingContainer container">
<div class="row align-items-center">
<div class="col-md-4 mt-3">
<h3>Trending</h3>
</div>
<div class="col-md-8 mt-3" *ngIf="timeSelectedValue">
<mat-button-toggle-group
name="fontStyle"
aria-label="Font Style"
(change)="onSelectionChange($event)"
[value]="timeSelectedValue"
>
<mat-button-toggle value="day">Today</mat-button-toggle>
<mat-button-toggle value="week">This Week</mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>
</div>
<!-- Skeleton loaders: show 8 when loading -->
<div class="d-flex mt-3" *ngIf="loading">
<div
*ngFor="let _ of [].constructor(8); let i = index" class="d-flex"
>
<div class="skeleton-card-item">
<!-- Card image skeleton -->
<div class="position-relative">
<ngx-skeleton-loader
[theme]="{
'border-radius': '12px',
height: '292px',
width: '192px',
margin: '0px 10px'
}"
></ngx-skeleton-loader>
<!-- Score placeholder skeleton -->
<ngx-skeleton-loader
[theme]="{
'border-radius': '12px',
height: '50px',
width: '50px',
position: 'absolute',
top: '100%',
left: '100%',
transform: 'translate(-50%, -50%)'
}"
></ngx-skeleton-loader>
</div>
<!-- Title placeholder skeleton -->
<ngx-skeleton-loader
appearance="line"
[theme]="{
'border-radius': '12px',
width: '198px',
'margin-top': '30px'
}"
></ngx-skeleton-loader>
<!-- Watchlist button placeholder skeleton -->
<ngx-skeleton-loader
appearance="line"
[theme]="{
'border-radius': '24px',
height: '40px',
width: '150px',
margin: '10px auto'
}"
></ngx-skeleton-loader>
</div>
</div>
</div>
<div id="swiperTrending" class="swiper-container mt-5 mb-5">
<div class="swiper-wrapper">
@for(show of trendingShows;track show.id;let index=$index){
<div class="swiper-slide">
<app-show-card-score
[show]="show"
[index]="index"
[routerLink]="
show.media_type === 'movie'
? ['/movie', show.id]
: show.media_type === 'tv'
? ['/tv', show.id]
: ['/unknown', show.id]
"
></app-show-card-score>
</div>
}
</div>
</div>
</div>
I’m using Angular with Swiper.js to display a trending list of shows fetched from the TMDB API. However, when the component loads, only one slide appears at first, and then after a brief moment, all slides load in. I want all slides to appear immediately after data is fetched.
I have tried this but none worked:
-Initializing Swiper after fetching the data.
-Destroying and reinitializing Swiper before loading new data.
-Making sure trendingShows updates before Swiper initializes.
-Delaying Swiper initialization slightly using setTimeout.
Firs shows the normal skeleton before data is fetched