Get dots in photo gallery working for carousel in Typescript / Phoenix Liveview

22 Views Asked by At

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>

enter image description here

0

There are 0 best solutions below