0

I have been trying to get this working but can't. I am using Astro (Tailwind and React, but not relevant here). I want to have one main image, that is replaced when you click on one of the smaller images that are mapped out from my collections data.

<div class="hidden gap-x-3 gap-y-5 px-3 md:grid md:grid-cols-3 md:px-5">
      <div
        class="min-h-96 aspect-w-1 aspect-h-1 lg:aspect-none col-span-3 w-full overflow-hidden rounded-md bg-gray-100 group-hover:opacity-75 lg:h-96"
      >
        <div class="h-96 min-w-full overflow-hidden rounded-lg bg-slate-50">
          <Image
            src={featureImage}
            alt={fiAlt}
            width="800"
            height="800"
            class="h-96 w-full object-cover"
            format="webp"
            quality="low"
            transition:name={`image-${slug}`}
            id="imagebox"
          />
        </div>
      </div>
      {
        images.map((image) => (
          <button
            id={image}
            class="imagechange h-50 aspect-w-1 aspect-h-1 col-span-1 w-full overflow-hidden rounded-md bg-gray-100 shadow-lg group-hover:opacity-75"
          >
            <Image
              src={image}
              alt={fiAlt}
              width="800"
              height="800"
              class="h-full w-full object-cover"
              format="webp"
              quality="low"
            />
          </button>
        ))
      }
    </div>

I tried this Javascript, but it did not work at all - Astro apparently cannot generate the right src from the collections data because I am using astro-assets I presume.

<script is:inline>
  window.addEventListener('DOMContentLoaded', (event) => {
    const img = document.getElementById("imagebox");
    const buttons = document.querySelectorAll('button.imagechange');

    buttons.forEach(button => {
      button.addEventListener('click', function() {
        img.src = button.querySelector('img').src;
        img.alt = button.querySelector('img').alt;
      });
    });
  });
</script>

Can anyone point me to the right direction?

  • In your first block of code, are you using an astro component or a React one? – Lucas David Ferrero Aug 27 '23 at 12:50
  • It was an astro file. I solved this issue now - I first managed to correct the JS and then realized the code would only run once on the whole website, which did not make much sense since these were dynamically created pages for each product in a webshop. So I proceeded to create a Web Component. – chris-origins Aug 27 '23 at 17:36

1 Answers1

0

As stated above, I changed it to be an astro custom element/web component so that the script would load every time it encountered this component.

The working code is:

---
const { images, featureImage, slug, alt } = Astro.props;
import { Image } from "astro:assets";
---

<image-box
  data-images={images}
  data-featureImage={featureImage}
  data-slug={slug}
  data-alt={alt}
>
  <div class="gap-x-3 gap-y-5 px-3 md:grid md:grid-cols-3 md:px-5">
    <div
      class="min-h-96 aspect-w-1 aspect-h-1 lg:aspect-none col-span-3 w-full overflow-hidden rounded-md bg-gray-100 group-hover:opacity-75 lg:h-96"
    >
      <div class="h-96 min-w-full overflow-hidden rounded-lg bg-slate-50">
        <Image
          id="mainImage"
          src={featureImage}
          alt={alt}
          width="800"
          height="800"
          class="h-96 w-full object-cover"
          format="webp"
          quality="low"
          transition:name={`image-${slug}`}
        />
      </div>
    </div>
    {
      images.map((image, index) => (
        <button
          key={index}
          data-src={image.src}
          data-alt={alt}
          class="imagechange h-50 aspect-w-1 aspect-h-1 col-span-1 w-full overflow-hidden rounded-md bg-gray-100 shadow-lg group-hover:opacity-75"
        >
          <Image
            src={image}
            alt={alt}
            width={image.width}
            height={image.height}
            class="h-full w-full object-cover"
            format="webp"
            quality="low"
          />
        </button>
      ))
    }
  </div>
</image-box>

<script>
  class ImageBox extends HTMLElement {
    constructor() {
      super();

      // Select the mainImage by id
      const mainImage = document.getElementById("mainImage");
      const buttons = this.querySelectorAll("button.imagechange");

      buttons.forEach((button) => {
        button.addEventListener("click", function () {
          const newSrc = button.getAttribute("data-src");
          const newAlt = button.getAttribute("data-alt");
          mainImage.src = newSrc;
          mainImage.alt = newAlt;
        });
      });
    }
  }

  customElements.define("image-box", ImageBox);
</script>