I am utilizing Swiper in several of my components, and I've encountered an issue when Angular routing changes especially routeParams eg. /route/:id – it doesn't function correctly. To address this, I implemented ngZone. This resolved the main Swiper functionality, but the thumbs Swiper is still behaving unexpectedly. I believe that rather than initializing twice, it would be more efficient to initialize once with both the main Swiper and thumb Swiper details. However, I am unsure about the syntax. Can someone please assist me with this?
Note: The objective is to ensure that Swiper works seamlessly when navigating between different routes.
html:
<div>
<swiper-container #swiper1 style="--swiper-navigation-color: #fff; --swiper-pagination-color: #fff" class="mySwiper"
thumbs-swiper=".mySwiper2" navigation="true" init="false">
<swiper-slide *ngFor="let slide of slides">
<img [src]="slide.image" />
</swiper-slide>
</swiper-container>
<swiper-container #swiper2 class="mySwiper2" space-between="10" slides-per-view="6" free-mode="true"
watch-slides-progress="true" init="false">
<swiper-slide *ngFor="let slide of slides">
<img [src]="slide.image" />
</swiper-slide>
</swiper-container>
</div>
css:
swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
display: flex;
justify-content: center;
align-items: center;
background-size: cover;
background-position: center;
img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
}
.mySwiper {
height: 600px;
width: 100%;
}
.mySwiper2 {
// defines height and width of thumbs swiper
height: 100px;
width: 100%;
box-sizing: border-box;
padding: 10px 0;
swiper-slide {
opacity: 0.6; // this set default opacity to all slides
}
.swiper-slide-thumb-active {
opacity: 1; // this reset the opacity one for the active slide
}
}
ts
import { CommonModule } from '@angular/common';
import {
Component,
OnInit,
CUSTOM_ELEMENTS_SCHEMA,
ViewChild,
ElementRef,
AfterViewInit,
NgZone,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-swiper-thumbs-vertical-dup-1',
standalone: true,
imports: [CommonModule],
templateUrl: './swiper-thumbs-vertical-dup-1.component.html',
styleUrl: './swiper-thumbs-vertical-dup-1.component.scss',
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class SwiperThumbsVerticalDup1Component implements OnInit, AfterViewInit {
@ViewChild('swiper1') swiper1!: ElementRef<any>;
@ViewChild('swiper2') swiper2!: ElementRef<any>;
slides: any[] = []
constructor(private zone: NgZone, private route: ActivatedRoute) { }
ngOnInit() {
this.routeSub = this.route.params.subscribe(params => {
const id = params['id'];
if (id == 1) {
this.slides = [
{ image: 'https://swiperjs.com/demos/images/nature-1.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-2.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-3.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-4.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-5.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-6.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-7.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-8.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-10.jpg' },
];
} else {
this.slides = [
{ image: 'https://swiperjs.com/demos/images/nature-6.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-7.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-8.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-10.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-1.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-2.jpg' },
{ image: 'https://swiperjs.com/demos/images/nature-3.jpg' },
];
}
});
}
ngAfterViewInit() {
this.zone.runOutsideAngular(() => {
const swiperParams = {
breakpoints: {
100: {
slidesPerView: 3,
},
640: {
slidesPerView: 5,
},
1024: {
slidesPerView: 6,
},
},
};
const swiperParams1 = {
spaceBetween: 10
};
Object.assign(this.swiper2.nativeElement, swiperParams1);
this.swiper1.nativeElement.initialize();
// now we need to assign all parameters to Swiper element
Object.assign(this.swiper2.nativeElement, swiperParams);
this.swiper2.nativeElement.initialize();
});
}
}
When we change the route, swiper is getting confused when the *ngFor
(slides) are getting updated, so to fix this, we can reinitialize the swiper-container
using the below code, which will ensure the swiper still works on params change!
code to reinitialize Swiper
if (this.swiper1?.nativeElement) {
this.swiper1.nativeElement.swiper.destroy();
this.swiper1.nativeElement.initialized = false;
this.swiper1.nativeElement.initialize();
}
if (this.swiper2?.nativeElement) {
this.swiper2.nativeElement.swiper.destroy();
this.swiper2.nativeElement.initialized = false;
this.swiper2.nativeElement.initialize();
}
Note: I have removed spaceBetween
property since its causing a wierd bug, when the slide movement gets offset by that value as the slides increase, I am unable to solve it, but it works without this property!
full code
import { CommonModule } from '@angular/common';
import {
Component,
OnInit,
CUSTOM_ELEMENTS_SCHEMA,
ViewChild,
ElementRef,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs';
import { register } from 'swiper/element';
register();
@Component({
selector: 'app-swiper',
standalone: true,
imports: [CommonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
templateUrl: './swiper.component.html',
})
export class SwiperComponent implements OnInit {
@ViewChild('swiper1') swiper1!: ElementRef<any>;
@ViewChild('swiper2') swiper2!: ElementRef<any>;
routeSub!: Subscription;
slides: any[] = [];
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.routeSub = this.route.params.subscribe((params) => {
const id = params['id'];
if (id == 1) {
this.slides = [
{ id: 1, image: 'https://swiperjs.com/demos/images/nature-1.jpg' },
{ id: 2, image: 'https://swiperjs.com/demos/images/nature-2.jpg' },
{ id: 3, image: 'https://swiperjs.com/demos/images/nature-3.jpg' },
{ id: 4, image: 'https://swiperjs.com/demos/images/nature-4.jpg' },
{ id: 5, image: 'https://swiperjs.com/demos/images/nature-5.jpg' },
{ id: 6, image: 'https://swiperjs.com/demos/images/nature-6.jpg' },
{ id: 7, image: 'https://swiperjs.com/demos/images/nature-7.jpg' },
{ id: 8, image: 'https://swiperjs.com/demos/images/nature-8.jpg' },
{ id: 9, image: 'https://swiperjs.com/demos/images/nature-10.jpg' },
];
} else {
this.slides = [
{ id: 10, image: 'https://swiperjs.com/demos/images/nature-6.jpg' },
{ id: 11, image: 'https://swiperjs.com/demos/images/nature-7.jpg' },
{ id: 12, image: 'https://swiperjs.com/demos/images/nature-8.jpg' },
{ id: 13, image: 'https://swiperjs.com/demos/images/nature-10.jpg' },
{ id: 14, image: 'https://swiperjs.com/demos/images/nature-1.jpg' },
{ id: 15, image: 'https://swiperjs.com/demos/images/nature-2.jpg' },
{ id: 16, image: 'https://swiperjs.com/demos/images/nature-3.jpg' },
];
}
if (this.swiper1?.nativeElement) {
this.swiper1.nativeElement.swiper.destroy();
this.swiper1.nativeElement.initialized = false;
this.swiper1.nativeElement.initialize();
}
if (this.swiper2?.nativeElement) {
this.swiper2.nativeElement.swiper.destroy();
this.swiper2.nativeElement.initialized = false;
this.swiper2.nativeElement.initialize();
}
});
}
ngAfterViewInit() {
const swiperParams = {
updateOnWindowResize: true,
breakpoints: {
100: {
slidesPerView: 3,
},
640: {
slidesPerView: 5,
},
1024: {
slidesPerView: 6,
},
},
};
const swiperParams1 = {};
Object.assign(this.swiper1.nativeElement, swiperParams1);
this.swiper1.nativeElement.initialize();
// now we need to assign all parameters to Swiper element
Object.assign(this.swiper2.nativeElement, swiperParams);
this.swiper2.nativeElement.initialize();
}
trackBy(index: number, slide: any) {
return slide.id;
}
}
html
<div>
<swiper-container
#swiper1
style="--swiper-navigation-color: #fff; --swiper-pagination-color: #fff"
class="mySwiper"
thumbs-swiper=".mySwiper2"
navigation="true"
init="false"
>
<swiper-slide *ngFor="let slide of slides">
<img [src]="slide.image" />
</swiper-slide>
</swiper-container>
<swiper-container
#swiper2
class="mySwiper2"
space-between="10"
slides-per-view="6"
free-mode="true"
watch-slides-progress="true"
init="false"
>
<swiper-slide *ngFor="let slide of slides">
<img [src]="slide.image" />
</swiper-slide>
</swiper-container>
</div>