I am writing a photo gallery from scratch in Typescript with a Phoenix Liveview template. I got it rendering with a typescript hook however I can't seem to get the dots functioning. I am sure I am doing something stupid but would love a second pair of eyes cause am a bit new to TS and Phoenix also.
Mainly it's the JS that I am trying to get working. Below is my code.
import LiveHook from "../lib/livehook";
const GallerySlider: LiveHook = {
mounted() {
const carousel: any = document.querySelector(".carousel") as HTMLElement;
const firstImg: HTMLImageElement = carousel.querySelectorAll(
"img",
)[0] as HTMLImageElement;
const arrowIcons: NodeListOf<HTMLElement> = document.querySelectorAll(
".wrapper i",
) as NodeListOf<HTMLElement>;
let isDragStart: boolean = false;
let isDragging: boolean = false;
let prevPageX: number;
let prevScrollLeft: number;
let positionDiff: number;
const showHideIcons = (): void => {
let scrollWidth: number = carousel.scrollWidth - carousel.clientWidth;
arrowIcons[0].style.display =
carousel.scrollLeft === 0 ? "none" : "block";
arrowIcons[1].style.display =
carousel.scrollLeft === scrollWidth ? "none" : "block";
};
arrowIcons.forEach((icon: any) => {
icon.addEventListener("click", () => {
let firstImgWidth = firstImg.clientWidth + 14;
carousel.scrollLeft +=
icon.id === "left" ? -firstImgWidth : firstImgWidth;
setTimeout(() => showHideIcons(), 60);
});
});
const autoSlide = (): any => {
if (
carousel.scrollLeft - (carousel.scrollWidth - carousel.clientWidth) >
-1 ||
carousel.scrollLeft <= 0
)
return;
positionDiff = Math.abs(positionDiff);
let firstImgWidth = firstImg.clientWidth + 14;
let valDifference = firstImgWidth - positionDiff;
if (carousel.scrollLeft > prevScrollLeft) {
return (carousel.scrollLeft +=
positionDiff > firstImgWidth / 4 ? valDifference : -positionDiff);
}
carousel.scrollLeft -=
positionDiff > firstImgWidth / 4 ? valDifference : -positionDiff;
};
//Dragger
const dragStart = (e: MouseEvent | TouchEvent): void => {
isDragStart = true;
prevPageX = "pageX" in e ? e.pageX : e.touches[0].pageX;
prevScrollLeft = carousel.scrollLeft;
};
const dragging = (e: MouseEvent | TouchEvent): void => {
if (!isDragStart) return;
e.preventDefault();
isDragging = true;
carousel.classList.add("dragging");
positionDiff =
"pageX" in e
? (e.pageX as number) - prevPageX
: e.touches[0].pageX - prevPageX;
carousel.scrollLeft = prevScrollLeft - positionDiff;
showHideIcons();
};
const dragStop = (): void => {
isDragStart = false;
carousel.classList.remove("dragging");
if (!isDragging) return;
isDragging = false;
autoSlide();
};
//Carousel dots
let carouselItem: HTMLCollectionOf<HTMLDivElement> =
carousel.getElementsByTagName("div");
let dots: HTMLElement | null = document.getElementById("dots");
let dotsChild: HTMLCollectionOf<HTMLLIElement> = document
.getElementById("dots")!
.getElementsByTagName("li");
for (let i: number = 0; i < carousel.children.length; i++) {
dots?.appendChild(document.createElement("li"));
dotsChild[i].classList.add("list-inline-item");
dotsChild[i].setAttribute("id", i.toString());
dotsChild[i].innerHTML = i.toString();
if (i === 0) {
dotsChild[i].classList.add("active");
}
dotsChild[i].addEventListener("click", carousel);
}
let dnum: string = "id";
for (let i: number = 0; i < carouselItem.length; i++) {
carouselItem[i].classList.remove("active");
if (dnum !== null) {
carouselItem[parseInt(dnum)].classList.add("active");
dotsChild[i].classList.remove("active");
dotsChild[parseInt(dnum)].classList.add("active");
}
}
carousel.addEventListener("mousedown", dragStart);
carousel.addEventListener("touchstart", dragStart);
document.addEventListener("mousemove", dragging);
carousel.addEventListener("touchmove", dragging);
document.addEventListener("mouseup", dragStop);
carousel.addEventListener("touchend", dragStop);
},
};
export default GallerySlider;
Snippet from Phoenix template & HTML markup
<div phx-hook="GallerySlider" id="gallerylider">
<div class="wrapper">
<i id="left" class="fa-solid fa-angle-left"></i>
<div class="carousel flex flex-row">
<%= for id <- image_ids() do %>
<img src={thumb_url(id)} class="rounded-2xl" id="image" />
<% end %>
</div>
<i id="right" class="fa-solid fa-angle-right"></i>
</div>
<ul id="dots" class="list-inline dots"></ul>
</div>
