Reputation: 3854
I want to create a custom image slider, where i can load images dynamically, This is a link of working example:
https://stackblitz.com/edit/angular-ivy-rwuxjd?file=src/app/app.component.html
Slider is working but there is one issue i want to hide current slide and translate incoming slide only. New slide should translate from extreme right. But in this code current slide is also translating.
Upvotes: 1
Views: 2816
Reputation: 57919
Sometime ago I used the ngb-carousel and animate to left-rigth and rigth-left (it's time ngb-carousel has no animation) in this SO (the second update) Since 8.0.0 you has animation.
I feel you can not use :enter and :left because only when enter the imagen is loaded. So, based in the before SO, you can define an animation like
const animation = [
state('outright', style({ transform: `translateX(100%)` })),
state('outleft', style({ transform: `translateX(-100%)` })),
transition('void=>inleft',[
style({transform:`translateX(0)`}),
]),
transition('void=>outleft',[
style({transform:`translateX(-100%)`}),
]),
transition('*=>inright',[
style({transform:`translateX(-100%)`}),
animate('260ms ease-in',style({ transform: `translateX(0)` }))
]),
transition('*=>inleft',[
style({transform:`translateX(100%)`}),
animate('260ms ease-in',style({ transform: `translateX(0)` }))
]),
transition('*=>outleft', [
animate('260ms ease-in', style({ transform: `translateX(-100%)` }))
]),
transition('*=>outright', [
animate('260ms ease-in',style({ transform: `translateX(100%)` }))
]),
]
see that a slider can be outleft,outrigth,inleft or inrigth
So I define an array like
slideControl: any[] = this.images.map((x,index)=>index ? 'outleft' : 'inleft')
And when we click next or prev we call to the function onSlide
onNext() {
if (this.counter != this.images.length - 1) {
this.counter++;
this.onSlide(this.counter,this.counter-1,'right')
}
}
onPrevious() {
if (this.counter > 0) {
this.counter--;
this.onSlide(this.counter,this.counter+1,'left')
}
}
onSlide(current,prev,direction) {
this.slideControl=this.slideControl.map((x, index) => {
return (index == current) ?'in' + direction :
(index == prev) ? 'out' + direction : x
})
}
The last piece of jigsaw are the .html
<div class="wrapper" >
<div *ngFor="let img of images; let i = index"
[@animImageSlider]="slideControl[i]">
<img #slide [src]="img" style="height:200px; width:200px" />
</div>
</div>
And the .css, See that this animation work if all the images are placed in the position top:0, left:0 of the wrapper
.wrapper{
overflow: hidden;
width:200px;
}
.wrapper::after {
display: block;
clear: both;
content: "";
}
.wrapper div{
float:left;
margin-right: -100%;
}
the stackblitz
Update Well, the function onSlide can be simply:
onSlide(current,prev,direction) {
this.slideControl[current]='in' + direction;
this.slideControl[prev]='out' + direction
}
And there're a point I don't like that it's the "hardcode" with of wrapper. We can take advantage of the event load and use a variable with in the way
width:number=0;
onLoad(el:any)
{
this.width=el.getBoundingClientRect().width
}
So, our .html can be like
<div class="wrapper" [style.width.px]="width" >
<div *ngFor="let img of images; let i = index"
[@animImageSlider]="slideControl[i]">
<img #slide (load)="i==0 && onLoad(slide)" [src]="img" />
</div>
</div>
See that the function "onLoad" it's only called for the first slide
NOTE: If we want a "infinite carousel" we can change reemplace the functions next and prev by
change(direction:string)
{
const incr=direction=='right'?1:-1
const prev=this.counter
this.counter=(this.counter+this.images.length+incr)%this.images.length
this.slideControl[this.counter]='in' + direction;
this.slideControl[prev]='out' + direction
}
And use
<button type="button" (click)="change('left')" >
Previous
</button>
<button type="button" (click)="change('right')">
Next
</button>
NOTE: I update the stackblitz with this two changes
Upvotes: 1