So I am creating a simple project gallery, and to do so I followed a W3schools tutorial on making a photo gallery and converting this to my needs. However with that tutorial the number of items is predefined, for mine, it is connected to MongoDB using Nodejs and stuff.
The original tutorial follows this html scheme:
<div class="section-projects-main-container">
<!-- Full-width images with number text -->
<div class="section-projects-project-container">
<div class="section-projects-project-title">Great Tree 1</div>
<div class="section-projects-project-date">21<span id="slashs">/</span>69<span id="slashs">/</span>4200</div>
<img class="section-projects-project-img" src="tree.jfif">
<div class="section-projects-project-description">This is a sample description, it will explain the project and basic about what this is going to be, and why it is so cool. This is a sample description, it will explain the project and basic about what this is going to be, and why it is so cool.</div>
<button class="section-projects-project-btn">Learn More</button>
</div>
<div class="section-projects-project-container">
<div class="section-projects-project-title">Great Tree 2</div>
<div class="section-projects-project-date">21/21/21</div>
<img class="section-projects-project-img" src="tree2.jfif">
<div class="section-projects-project-description">This is a sample description, it will explain the project and basic about what this is going to be, and why it is so cool. This is a sample description, it will explain the project and basic about what this is going to be, and why it is so cool.</div>
</div>
<!-- Next and previous buttons -->
<a class="section-projects-btn-prev" onclick="plusSlides(-1)">❮</a>
<a class="section-projects-btn-next" onclick="plusSlides(1)">❯</a>
<!-- Thumbnail images -->
<div class="section-projects-thumbnail-mtitle">Other Projects</div>
<div class="section-projects-thumbnail-row">
<div class="section-projects-thumbnail-col" >
<img class="section-projects-thumbnail-img cursor" src="tree.jfif" onclick="currentSlide(1)" alt="The Woods">
<h3 class="section-projects-thumbnail-title">Project Title 1</h3>
<h4 class="section-projects-thumbnail-date">21/69/4300</h4>
</div>
<div class="section-projects-thumbnail-col">
<img class="section-projects-thumbnail-img cursor" src="tree2.jfif" onclick="currentSlide(8)" alt="Cinque Terre">
<h3 class="section-projects-thumbnail-title">Project Title 2</h3>
<h4 class="section-projects-thumbnail-date">21/69/4200</h4>
</div>
</div>
</div>
And the JS used was :
var slideIndex = 1;
showSlides(slideIndex);
// Next/previous controls
function plusSlides(n) {
showSlides(slideIndex += n);
}
// Thumbnail image controls
function currentSlide(n = id) {
showSlides(slideIndex = id);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("section-projects-project-container");
var column = document.getElementsByClassName("section-projects-thumbnail-col");
var dots = document.getElementsByClassName("section-projects-thumbnail-img");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
column[i].className = column[i].className.replace(" active", "");
column[i].style.display = "inline-block";
}
slides[slideIndex-1].style.display = "inline-flex";
column[slideIndex-1].className += " active";
column[slideIndex-1].style.display = "none";
}
So the onclick was passed into <img> of each thumbnail image, and the specific order of the thumbnail was listed into it's parameter as such currentSlide(n).
Now with EJS, the html is as such :
<div class="section-projects-main-container">
<% projectdetails.forEach(project => { %>
<!-- Full-width images with number text -->
<div class="section-projects-project-container">
<div class="section-projects-project-title"><%= project.projectName %></div>
<div class="section-projects-project-date"><%= project.projectDate %></div>
<img class="section-projects-project-img" src="data:<%=project.img.contentType%>;base64,<%=project.img.data.toString('base64')%>">
<div class="section-projects-project-description"><%= project.projectDescription %></div>
<button class="section-projects-project-btn">Learn More</button>
</div>
<% }) %>
<!-- Next and previous buttons -->
<a class="section-projects-btn-prev" onclick="plusSlides(-1)">❮</a>
<a class="section-projects-btn-next" onclick="plusSlides(1)">❯</a>
<!--Thumbnail images-->
<div class="section-projects-thumbnail-mtitle">Other Projects</div>
<div class="section-projects-thumbnail-row">
<% projectdetails.forEach(item => { %>
<div class="section-projects-thumbnail-col" >
<img class="section-projects-thumbnail-img cursor" src="data:<%=item.img.contentType%>;base64,<%=item.img.data.toString('base64')%>" onclick="currentSlide()" alt="The Woods">
<h3 class="section-projects-thumbnail-title"><%= item.projectName %></h3>
<h4 class="section-projects-thumbnail-date"><%= item.projectDate %></h4>
</div>
<% }) %>
</div>
</div>
But I am not sure how to pass the _id of each project into the thumbnail onclick function. I have tried sending the _id into the html <div id="hiddendiv" style="color: white; display: none; position: relative;"><%=project.id %></div> and then retrieving this value via JS and running the function as such. But this does not work properly.
Is there any solution to this? and if not what is the next possible way to make the currentSlide() function without a variable being needed?.
THank you
I would probably skip using a hidden div as some sort of data keeper. Use data-id attribute instead: data-id="<%=project.id %>"
Or on the other hand, why not just do onclick="currentSlide(<%= project.id %>)"?
I would gladly like to help you more, but I don't know what's the point of the JavaScript above and what it should do.
Also, I would probably add an event click listener to every <div class="section-projects-project-container"> and then in the JavaScript got the data-id using: getAttribute('data-id'). You can get the element that called the function using this so you could probably then do:
this.getAttribute('data-id')
Edit:
Well, if it's really that similar to that W3 example - why not just do this?
<% for (var i = 0; i < projectdetails.length; i++) { %>
<div class="section-projects-thumbnail-col">
<img
class="section-projects-thumbnail-img cursor"
src="data:<%= projectdetails[i].img.contentType %>;base64,<%= projectdetails[i].img.data.toString('base64') %>"
onclick="currentSlide(<%= i %>)"
alt="Alternate text"
/>
<h3 class="section-projects-thumbnail-title"><%= projectdetails[i].projectName %></h3>
<h4 class="section-projects-thumbnail-date"><%= projectdetails[i].projectDate %></h4>
</div>
<% } %>
Hopefully it works, but the principle is clear
Related
I made a slider with a series of images. I created two buttons (prev and next) that allow browsing the images.
I created also two divs where I put the slide's number and title.
My goal is to change the image, number, and title of the slide simultaneously each time a click event on prev or next buttons occurs.
I have started programming some months ago and I am having difficulties associating images with corresponding titles and numbers.
Could someone help me complete my code?
Actually, the following code works for me to show the image on click but is not complete.
I would like to change all the elements (image, title and number) at the same time after click.
More details on the picture:Screen of the homepage
// Carousel
let sliderImage = document.querySelector(".sliderImage");
let images = [
"carousel1.jpg",
"carousel2.jpg",
"carousel3.jpg",
"carousel4.jpg",
"carousel5.jpg",
"carousel6.jpg",
"carousel7.jpg",
];
let i = 0; // Current image index
// I have already created in html file 2 btns with "onclick" event
// that trigger the following functions:
function prev() {
if (i <= 0) i = images.length;
i--;
return getSlideImg();
}
function next() {
if (i >= images.length - 1) i = -1;
i++;
return getSlideImg();
}
function getSlideImg() {
return sliderImage.setAttribute("src", "img/" + images[i]);
}
<!-- Carousel -->
<div class="carousel-container">
<div class="carousel-slide">
<img src="./img/carousel1.jpg" alt="" class="sliderImage"/>
<!-- Carousel card -->
<div class="carousel__card-container">
<div class="carousel__card-title">Soggiorno</div>
<div class="carousel__slide-data">
<div class="slide__number">01</div>
<div class="slide__loader">
<div class="loader__line-grey">
<div class="loader__line-white"></div>
</div>
</div>
</div>
</div>
<!-- Carousel buttons -->
<div class="carousel-btn">
<a href="#" class="button left-arrow bottone" id="prevBtn" onclick="prev()">
<i class="ri-arrow-left-s-line btn-icon-small"></i>
</a>
<a href="#" class="button right-arrow bottone" id="nextBtn" onclick="next()">
<i class="ri-arrow-right-s-line btn-icon-small"></i>
</a>
</div>
</div>
</div>
set all values inside getSlideImg function so everything will update with corresponding image
// Carousel
let sliderImage = document.querySelector(".sliderImage"),
container = document.querySelector(".carousel-container")
let images = [
"carousel1.jpg",
"carousel2.jpg",
"carousel3.jpg",
"carousel4.jpg",
"carousel5.jpg",
"carousel6.jpg",
"carousel7.jpg",
];
let i = 0; // Current image index
// I have already created in html file 2 btns with "onclick" event
// that trigger the following functions:
function prev() {
if (i <= 0) i = images.length;
i--;
return getSlideImg();
}
function next() {
if (i >= images.length - 1) i = -1;
i++;
return getSlideImg();
}
function getSlideImg() {
container.querySelector(".slide__number").innerText = i + 1
container.querySelector(".carousel__card-title").innerText = images[i]
return sliderImage.setAttribute("src", "img/" + images[i]);
}
// for onload
getSlideImg()
<!-- Carousel -->
<div class="carousel-container">
<div class="carousel-slide">
<img src="./img/carousel1.jpg" alt="" class="sliderImage"/>
<!-- Carousel card -->
<div class="carousel__card-container">
<div class="carousel__card-title">Soggiorno</div>
<div class="carousel__slide-data">
<div class="slide__number">01</div>
<div class="slide__loader">
<div class="loader__line-grey">
<div class="loader__line-white"></div>
</div>
</div>
</div>
</div>
<!-- Carousel buttons -->
<div class="carousel-btn">
<a href="#" class="button left-arrow bottone" id="prevBtn" onclick="prev()">
<i class="ri-arrow-left-s-line btn-icon-small">prev</i>
</a>
<a href="#" class="button right-arrow bottone" id="nextBtn" onclick="next()">
<i class="ri-arrow-right-s-line btn-icon-small">next</i>
</a>
</div>
</div>
</div>
User can, by pressing a button, select a particular topic of interest. When that happens, various divs will either become visible or invisible depending on whether that div has a link referring to that topic.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
var topics = [];
for (j = 0; j < children.length; j++) {
topics.push(children[j].getAttribute("asp-route-name"));
document.getElementById("firstTest").innerHTML = children[j].toString();
}
var b = topics.includes(topic);
if (b == true) {
var parentId = document.getElementById(topicAreas[i]).parentNode.id;
document.getElementById(parent).style.display = 'block';
} else {
document.getElementById(parent).style.display = 'none';
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
The trouble, as far as I can tell, begin early in the JS part. I can see that when a do var children=topicAreas[i].children, I get nothing.
I hope this is what you're trying to do. Based on what button you click, respective div is displayed.
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
var topicAreas = area.getElementsByClassName("topicArea");
for (i = 0; i < topicAreas.length; i++) {
var children = topicAreas[i].children;
for (j = 0; j < children.length; j++) {
var parentId = topicAreas[i].parentNode.id;
if(children[j].getAttribute("asp-route-name") === topic){
document.getElementById(parentId).style.display = 'block';
}else{
document.getElementById(parentId).style.display = 'none';
}
}
}
}
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
Children isn't the issue. When you run your code you get the error "Uncaught TypeError: Cannot set property 'innerHTML' of null". Looking at your code where you are using .innerHTML, we see that you are trying to reference an element that you don't have in this code:
document.getElementById("firstTest")
Now, after adding that, you still have some items that you should change.
asp-action and asp-route-name are invalid HTML. Are you using a
framework that requires this syntax?
Don't use .getElementsByClassName().
Use .querySelectorAll() and Array.forEach() on the result for
easier looping.
Don't use .innerHTML when you aren't working with HTML strings as there are security and performance implications to doing so.
Avoid inline styles when you can. Using them causes duplication of code and code is harder to scale. Instead, use CSS classes and the .classList API.
It's not super clear exactly what is supposed to happen when clicking your buttons, but see the updated code below:
function GetPostsByTopic(topic) {
var area = document.getElementById("postArea");
// Don't use .getElementsByClassName() as it provides a live node list
// and causes quite a performance hit, especially when used in loops.
// Use .querySelectorAll() and then use .forEach() on the collection that
// it returns to iterate over them.
area.querySelectorAll(".topicArea").forEach(function(area){
var topics = [];
// No need for children, here. Again, use .querySelectorAll()
area.querySelectorAll("*").forEach(function(child) {
topics.push(child.getAttribute("asp-route-name"));
document.getElementById("firstTest").textContent = child.getAttribute("asp-route-name");
});
if (topics.indexOf(topic) > -1) {
// Don't use inline styles if you can avoid it.
// Instead use pre-made classes.
area.classList.add("hidden");
}
else {
area.classList.remove("hidden");
}
});
}
/* Use CSS classes when possible instead of inline styles */
.hidden { display:none; }
<div class="topicBox">
<button class="topicButton" onclick="GetPostsByTopic('Pets')">Pets</button>
<button class="topicButton" onclick="GetPostsByTopic('Vacation')">Vacation</button>
</div>
<div id="postArea">
<div class="post" id="post1">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
<div class="post" id="post2">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Vacation">Vacation</a>
</div>
</div>
<div class="post" id="post3">
<div class="topicArea">
<a asp-action="Topic" asp-route-name="Pets">Pets</a>
</div>
</div>
</div>
<div id="firstTest"></div>
I am trying to show all images with for loop. I have saved paths of images in Cubeimage array. And now I am trying to display them in <img>, but I get an error. How to write async code so it would work?
<div class="row">
<% for (var i = 0; i < Cubeimage.length; i++) { %>
<div class="column rounded border d-flex align-items-center">
<img class="demo cursor align-middle" src="<%= Cubeimage[i].image_path; =%>" style="width:100%;" onclick="currentSlide(1)" alt="The Woods">
</div><% } %>
Error:missing ) after argument list in /home/ubuntu/back_end/views/products_cube.ejs while compiling ejs If the above error is not helpful, you may want to try EJS-Lint: github.com/RyanZim/EJS-Lint Or, if you meant to create an async function, pass async: true as an option. SyntaxError: missing ) after argument list in /home/ubuntu/back_end/views/products_cube.ejs while compiling ejs
The solution found by the OP, and originally added to the answer:
<div class="row">
<% Cubeimage.forEach(function(cube){ %>
<div class="column rounded border d-flex align-items-center">
<img class="demo cursor align-middle" src="<%= cube.image_path; %>" style="width:100%;" onclick="currentSlide(1)" alt="Cube">
</div>
<% }); %>
</div>
I'm making an e-commerce website, where i'm allowing a user to upload up to 3 images of the item that the user is willing to sell, the images are displayed in a caroussel and are stored in my database.
I'm using foreach php loop to display all the images in a caroussel, the problem is that, it's working only for the first image (normally displayed), and once i click on "next", everything disapeers from the other items except the one i'm browsing.
if($total_row > 0)
{
foreach( $result as $row ){
$output .= '
<div class="box product item">
<div class="product__img">
<div class="slideshow-container">
<div class="mySlides ">
<img class="product__img" src="images/'.$row["folder"].'/'.$row["image1"].'" style="width:100%">
</div>
<div class="mySlides ">
<img class="product__img" src="images/'.$row["folder"].'/'.$row["image2"].'" style="width:100%">
</div>
<div class="mySlides ">
<img class="product__img" src="images/'.$row["folder"].'/'.$row["image3"].'" style="width:100%">
</div>
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
</div>
<div class="product__details">
<div class="product__details__title">
<h4>'.$row["name"].'</h4>
</div>
<div class="product__details__price">
<h3 " class="text-danger">'.intval($row["price"]).' دج' .'</h3>
</div>
</div>
<div class="product__contact">
<hr class="style11">
<i class="far fa-envelope"></i>
<input class="product__contact__btn" type="submit" value=" Contacter vendeur"><br><br>
<input class="product__contact__comparateur" type="checkbox" name="comparateur" value="comparateur"> Ajouter au comparateur <br>
</div>
</div>
';
}
}
And this is the JS i'm using for the caroussel:
var slideIndex = 1;
showSlides(slideIndex);
function plusSlides(n) {
showSlides(slideIndex += n);
}
function currentSlide(n) {
showSlides(slideIndex = n);
}
function showSlides(n) {
var i;
var slides = document.getElementsByClassName("mySlides");
if (n > slides.length)
{
slideIndex = 1
}
if (n < 1) {
slideIndex = slides.length
}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slides[slideIndex-1].style.display = "block";
}
DB:
Thanks for helping me.
Please note that using carousel for each product items with different images requires unique id or class ("mySlides"), as it seems all of your product images are using same carousel class that is why clicking on one product next button is affecting the other products items also which are using same class for carousel, so try identifying the click on current item container only so it won't affect other products with same carousel class.
I think you are not storing 3 images into database kindly check that images are being store are not.Then try to store images through loop against every product.
I think this is the issue.
Hope so this will help you.
I have been researching trying to figure out why its doing this, maybe I just dont understand modals. IDK.
Anyways what is happening is I started with a light box: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_js_lightbox
and changed the body to:
<body>
<h2 style="text-align:center">Title</h2>
<div class="row">
<div class="column">
<img src="img_nature.jpg" style="width:100%"
onclick="openModal();currentSlide(1)"
class="hover-shadow cursor">
</div>
</div>
<div id="myModal" class="modal">
<span class="close cursor" onclick="closeModal()">×</span>
<div class="modal-content">
<div class="mySlides">
<div class="numbertext">1 / 4</div>
<img src="img_nature_wide.jpg" style="width:100%">
</div>
<div class="mySlides">
<div class="numbertext">2 / 4</div>
<img src="img_fjords_wide.jpg" style="width:100%">
</div>
<div class="mySlides">
<div class="numbertext">3 / 4</div>
<img src="img_mountains_wide.jpg" style="width:100%">
</div>
<div class="mySlides">
<div class="numbertext">4 / 4</div>
<img src="img_lights_wide.jpg" style="width:100%">
</div>
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
<div class="caption-container">
<p id="caption"></p>
</div>
</div>
</div>
to create a single image in the modal, and to scroll through it. I love it, and I thought that it would solve my issue. Alas
When I implemented it in my web page it worked. but then I copied and pasted, and it in another area of the page, changed the images, but it is still showing the original images from the first modal. So I dont know where to turn.
I have 0 experience in jscript, jquery. (those classes are yet to come in my schooling...).
I was thinking:
1.) have the images on an external html page and import that I have looked at AJAX, but im confused. (dont necessarily want to use bootstrap)
I have looked at these resources, and they kinda help but again, I dont know how to craft them to my needs.
using Bootstrap
modals, nonimported html
modals
See the Pen Work issue by Michael Barnhouse (#Kardee785) on CodePen.
So as Curious 13, and Nate Whittaker Suggested I needed to make each section have its own unique Id. I had posted that that didn't work, and the reason it didnt work was because my .js wasnt reading/importing what to display. So I had to create a var in js (named modalId), and then call that information into the opening, closing, and navigating of the modal.
Here is the .js, I had one of my friends help me with.
function openModal(modalId) {
document.getElementById(modalId).style.display = "block";
}
function closeModal(modalId) {
document.getElementById(modalId).style.display = "none";
}
var slideIndex = 1;
showSlides(slideIndex);
function plusSlides(modalId, n) {
showSlides(modalId, slideIndex += n);
}
function currentSlide(modalId, n) {
showSlides(modalId, slideIndex = n);
}
function showSlides(modalId, n) {
var i;
var modal = document.getElementById(modalId);
var slides = modal.getElementsByClassName("mySlides");
var captionText = document.getElementById("caption");
if (n > slides.length) {slideIndex = 1}
if (n < 1) {slideIndex = slides.length}
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
captionText.innerHTML = dots[slideIndex-1].alt;
}