In my angular application, I have 4 swiper slide, which i want to render conditionally. But its not working properly. I have added images as well at bottom.
Issue - On initial load all swiper are rendering properly with 4 slides per view. But suppose if select swiper_1 then its showing 1 slide per view but according to swiperParam it should show 4 slide per view. If I select others like swiper_2, or swiper_3, then its showing 4 slides per view, and then if i select all then all swiper are showing 4 slide per view except the previous selected swiper "swiper_2 or swiper_3".
I think the parameters are not getting applied properly.
Typescript ->
import { CommonModule } from '@angular/common';
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, NgZone, QueryList, Renderer2, ViewChild, ViewChildren, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-swiper-testing',
standalone: true,
imports: [CommonModule],
templateUrl: './swiper-testing.component.html',
styleUrls: ['./swiper-testing.component.scss'],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
encapsulation: ViewEncapsulation.None,
})
export class SwiperTestingComponent {
constructor(private el: ElementRef, private cdRef: ChangeDetectorRef, private ngZone: NgZone, private renderer: Renderer2) { }
@ViewChild('swiper_1') swiper_1!: ElementRef;
@ViewChild('swiper_2') swiper_2!: ElementRef;
@ViewChild('swiper_3') swiper_3!: ElementRef;
@ViewChild('swiper_4') swiper_4!: ElementRef;
selectedCategories: string = 'all';
swiperParams = {
loop: false,
slidesPerView: 1,
spaceBetween: 24,
breakpoints: {
640: {
slidesPerView: 2,
},
1024: {
slidesPerView: 3,
},
1200: {
slidesPerView: 4,
},
1500: {
slidesPerView: 4.5,
},
1700: {
slidesPerView: 5,
},
1900: {
slidesPerView: 5.5,
},
},
navigation: true,
};
ngAfterViewInit() {
this.swiper_1Swiper();
this.swiper_2Swiper();
this.swiper_3Swiper();
this.swiper_4Swiper();
}
categoriesSelect(value: string) {
if (this.selectedCategories === value) return;
this.selectedCategories = value;
this.cdRef.detectChanges();
// Let Angular fully update the view first
this.ngZone.runOutsideAngular(() => {
setTimeout(() => {
this.ngZone.run(() => {
if (value === 'all' || value === 'swiper_1') this.swiper_1Swiper();
if (value === 'all' || value === 'swiper_2') this.swiper_2Swiper();
if (value === 'all' || value === 'swiper_3') this.swiper_3Swiper();
if (value === 'all' || value === 'swiper_4') this.swiper_4Swiper();
});
}, 0);
});
}
swiper_1Swiper() {
if (this.swiper_1?.nativeElement) {
const swiperEl = this.swiper_1.nativeElement;
Object.assign(swiperEl, this.swiperParams );
swiperEl.initialize();
}
}
swiper_2Swiper() {
if (this.swiper_2?.nativeElement) {
const swiperEl = this.swiper_2.nativeElement;
Object.assign(swiperEl, this.swiperParams);
swiperEl.initialize();
}
}
swiper_3Swiper() {
if (this.swiper_3?.nativeElement) {
const swiperEl = this.swiper_3.nativeElement;
Object.assign(swiperEl, this.swiperParams);
swiperEl.initialize();
}
}
swiper_4Swiper() {
if (this.swiper_4?.nativeElement) {
const swiperEl = this.swiper_4.nativeElement;
Object.assign(swiperEl, this.swiperParams);
swiperEl.initialize();
}
}
}
HTML ->
<div>
<div class="main">
<div class="filter-container d-flex justify-content-between align-items-start">
<button type="button" class="btn btn-primary selected" (click)="categoriesSelect('all')">All
swiper</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_1')">swiper 1</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_2')">swiper 2</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_3')">swiper 3</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_4')">swiper 4</button>
</div>
<div class="d-flex flex-column gap-4 mt-48">
<div class="cards-swiper-container"
*ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_1'">
<h4 class="mb-0">swiper_1 </h4>
<div class="navigation-wrapper"></div>
<swiper-container class="mySwiper" init="false" #swiper_1>
<swiper-slide *ngFor="let item of [1,2,3,4,5,6,7,8];">
</swiper-slide>
</swiper-container>
</div>
<div class="cards-swiper-container" *ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_2'">
<h4 class="mb-0">swiper_2 </h4>
<div class="navigation-wrapper"></div>
<swiper-container class="mySwiper" init="false" #swiper_2>
<swiper-slide *ngFor="let item of [1,2,3,4,5,6,7,8];">
</swiper-slide>
</swiper-container>
</div>
<div class="cards-swiper-container"
*ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_3'">
<h4 class="mb-0">swiper_3 </h4>
<div class="navigation-wrapper"></div>
<swiper-container class="mySwiper" init="false" #swiper_3>
<swiper-slide *ngFor="let item of [1,2,3,4,5,6,7,8];">
</swiper-slide>
</swiper-container>
</div>
<div class="cards-swiper-container" *ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_4'">
<h4 class="mb-0">swiper_4 </h4>
<div class="navigation-wrapper"></div>
<swiper-container class="mySwiper" init="false" #swiper_4>
<swiper-slide *ngFor="let item of [1,2,3,4,5,6,7,8];">
</swiper-slide>
</swiper-container>
</div>
</div>
</div>
</div>
All selected ->
Selected Swiper_1 ->
Selected Swiper_2 ->
Selected All again ->
To create more readable code, create a swiper component which encapsulates the swiper code.
The advantage of this, is when the component is created/destroyed. You will have a fresh initialization of each element.
@Component({
selector: 'app-swiper-element',
standalone: true,
imports: [],
template: `
<swiper-container class="mySwiper" init="false" #swiper>
<swiper-slide *ngFor="let item of items;">
</swiper-slide>
</swiper-container>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
encapsulation: ViewEncapsulation.None,
})
export class SwiperElementComponent {
@Input() items = [1,2,3,4,5,6,7,8];
@ViewChild('swiper') swiper!: ElementRef;
@Input() swiperParams: any = null;
ngAfterViewInit() {
this.initialize();
}
// make swiper react dynamically to @Input changes
// ngOnChanges() {
// this.initialize();
// }
initialize() {
if (this.swiper?.nativeElement && this.swiperParams) {
const swiperEl = this.swiper.nativeElement;
Object.assign(swiperEl, this.swiperParams );
swiperEl.initialize();
// this.cdRef.detectChanges(); // <- add this if needed.
}
}
}
Now all we need to do is to add SwiperElementComponent
to the imports array of the parent component and simplify the code as below.
@Component({
selector: 'app-swiper-testing',
standalone: true,
imports: [CommonModule, SwiperElementComponent], // <- add here!
templateUrl: './swiper-testing.component.html',
styleUrls: ['./swiper-testing.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class SwiperTestingComponent {
constructor(private el: ElementRef, private cdRef: ChangeDetectorRef, private ngZone: NgZone, private renderer: Renderer2) { }
selectedCategories: string = 'all';
swiperParams = {
loop: false,
slidesPerView: 1,
spaceBetween: 24,
breakpoints: {
640: {
slidesPerView: 2,
},
1024: {
slidesPerView: 3,
},
1200: {
slidesPerView: 4,
},
1500: {
slidesPerView: 4.5,
},
1700: {
slidesPerView: 5,
},
1900: {
slidesPerView: 5.5,
},
},
navigation: true,
};
categoriesSelect(value: string) {
if (this.selectedCategories === value) return;
this.selectedCategories = value;
this.cdRef.detectChanges();
}
}
In the HTML, just pass in the params to this component.
<div>
<div class="main">
<div class="filter-container d-flex justify-content-between align-items-start">
<button type="button" class="btn btn-primary selected" (click)="categoriesSelect('all')">All
swiper</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_1')">swiper 1</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_2')">swiper 2</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_3')">swiper 3</button>
<button type="button" class="btn btn-primary" (click)="categoriesSelect('swiper_4')">swiper 4</button>
</div>
<div class="d-flex flex-column gap-4 mt-48">
<div class="cards-swiper-container"
*ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_1'">
<h4 class="mb-0">swiper_1 </h4>
<div class="navigation-wrapper"></div>
<app-swiper-element [swiperParams]="swiperParams">
</app-swiper-element>
</div>
<div class="cards-swiper-container" *ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_2'">
<h4 class="mb-0">swiper_2 </h4>
<app-swiper-element [swiperParams]="swiperParams">
</app-swiper-element>
</div>
<div class="cards-swiper-container"
*ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_3'">
<h4 class="mb-0">swiper_3 </h4>
<div class="navigation-wrapper"></div>
<app-swiper-element [swiperParams]="swiperParams">
</app-swiper-element>
</div>
<div class="cards-swiper-container" *ngIf="selectedCategories === 'all' || selectedCategories === 'swiper_4'">
<h4 class="mb-0">swiper_4 </h4>
<div class="navigation-wrapper"></div>
<app-swiper-element [swiperParams]="swiperParams">
</app-swiper-element>
</div>
</div>
</div>
</div>