Same JavaScript function over multiple elements

Hello, all,

I am currently developing a portfolio for an architecture firm. I have added a function for a draggable horizontal carousel. I want the function to apply to each of the listings, however it only works on the first. I have tried writing a forEach loop in the javascript but it doesn’t seem the work. GIF attached below. (sorry for the terrible quality, had to compress)

2023-10-02 at 13.35.55 - Beige Blackbird

The code for the javascript is as follows:

let sliderContainer = document.querySelector('.slider-container');
let innerSlider = document.querySelector('.inner-slider');

let pressed = false;
let startX;
let x;

sliderContainer.addEventListener("mousedown", (e) => {
	pressed = true;
	startX = e.offsetX - innerSlider.offsetLeft;
	sliderContainer.style.cursor = "grabbing";
});

sliderContainer.addEventListener("mouseenter", () => {
	sliderContainer.style.cursor = "grab";
});

sliderContainer.addEventListener("mouseup", () => {
	sliderContainer.style.cursor = "grab";
	pressed = false;
});

sliderContainer.addEventListener("mousemove", (e) => {
	if (!pressed) return;
	e.preventDefault();

	x = e.offsetX;
});

sliderContainer.addEventListener("mousemove", (e) => {
	if (!pressed) return;
	e.preventDefault();

	x = e.offsetX;

	innerSlider.style.left = `${x - startX}px`;

  checkBoundary();
});

const checkBoundary = () => {
	let outer = sliderContainer.getBoundingClientRect();
	let inner = innerSlider.getBoundingClientRect();

	if (parseInt(innerSlider.style.left) > 0) {
		innerSlider.style.left = "0px";
	}

	if (inner.right < outer.right) {
		innerSlider.style.right = `-${inner.width - outer.width}px`;
	}
};

and this is the code for the project listings

<div class=" mx-auto flex justify-center min-w-full">
	<ul class="projectLength">
		<?php if ($projectsPage = page('projects')): ?>
		<?php foreach ($projectsPage->children()->listed() as $project): ?>
		<li class="my-5 section">
			<div class="slider-container ">
				<ul class="inner-slider">
					<!-- Project Tags -->
					<div class="min-w-max min-h-fit px-10">
						<span class="flex flex-col">
							<span class="flex mb-2">
								<div class="w-10 h-10 bg-black"></div>
							</span>
							<span class="text-black"><?= $project->title()->esc() ?></span>
							<span class="text-gray-500 uppercase text-sm"><?= $project->location() ?></span>
							<ul class="my-4">
								<?php if ($project->typology()->isNotEmpty()): ?>
								<li class="flex flex-col my-2">
									<span class="text-sm text-black capitalize">Typology</span>
									<span class="text-sm text-gray-500"><?= $project->typology() ?></span>
								</li>
								<?php endif ?>
								<?php if ($project->Plotarea()->isNotEmpty()): ?>
								<li class="flex flex-col my-2">
									<span class="text-sm text-black capitalize">Plot Area</span>
									<span class="text-sm text-gray-500"><?= $project->Plotarea() ?></span>
								</li>
								<?php endif ?>
								<?php if ($project->Builtarea()->isNotEmpty()): ?>
								<li class="flex flex-col my-2">
									<span class="text-sm text-black capitalize">Built Area</span>
									<span class="text-sm text-gray-500"><?= $project->Builtarea() ?></span>
								</li>
								<?php endif ?>
								<?php if ($project->levels()->isNotEmpty()): ?>
								<li class="flex flex-col my-2">
									<span class="text-sm text-black capitalize">Levels</span>
									<span class="text-sm text-gray-500"><?= $project->levels() ?></span>
								</li>
								<?php endif ?>
							</ul>
						</span>

					</div>
					<!-- End of Project Tags -->
					
					<!-- Project Images -->
					<?php foreach ($project->images() as $image) : ?>
					<li class="min-w-fit">
						<?php if ($image->caption()->isNotEmpty()) : ?>
						<figure class="flex card">
							<img src="<?= $image->crop(500, 500)->url() ?>" class="" alt="<?= $image->alt() ?>" />
							<figcaption class="px-10 text-sm w-100">
								<?= $image->caption()->smartypants() ?>
							</figcaption>
						</figure>
						<?php else: ?>
						<figure>
							<img src="<?= $image->crop(500, 500)->url() ?>" class="" alt="<?= $image->alt() ?>" />
						</figure>
						<?php endif ?>
					</li>
					<!-- End of Project Images -->
					<?php endforeach ?>
					
				</ul>
			</div>
		</li>
		<?php endforeach ?>
	</ul>
	<?php endif ?>
</div>

I followed this tutorial to create the slider – How to Create a Draggable Carousel Using Vanilla JavaScript

Thank you in advance!

This is more of a javascript function than a Kirby question.

let sliderContainer = document.querySelector('.slider-container');
let innerSlider = document.querySelector('.inner-slider');

This is selecting only the first match : Document: querySelector() method - Web APIs | MDN

If you want to match all, you need Document: querySelectorAll() method - Web APIs | MDN

But you probably want unique IDs (or other discriminating attribute in your html) so that your eventListeners are bound to the proper carousel.

Hi, Thiousi,

Thank you for your response! I know it’s more javascript related but was wondering whether the php had anything to do with it. I have also tried using document.querySelectorAll however the function stops working, and I get the error:

Uncaught TypeError: sliderContainer.addEventListener is not a function
    at index.js:8:17

Any idea on how I could add unique IDs for each listing that will correspond to the function? Sorry, I am new to development at this scale :frowning:

no, this is purely a JS issue.

You don’t need ids, but you need to add the event listener to each element, so do a sliderContainer.ForEach loop, see the MDN docs linked above.

Thank you! Using a forEach loop worked.