How to write a Function that collect and display images in modal - javascript

i have this function which collect the image and display them in a gallery:
let gallery = document.getElementById("gallery");
let galleryItemsData = [
{
id: "UX",
img: "images/UX/BrandBoard.png",
title: "Brand Board",
},
{
id: "CMlogo",
img: "images/123CleanMe/mockup (12).png",
title: "123 Clean Me",
}
];
let generateGallery = () => {
return (gallery.innerHTML = galleryItemsData.map((x) => {
let { id, img, title, } = x;
return `
<div class="imgContainer" id="${id}" >
<p class="title">${title}</p>
<img class="galleryImg" id="${id}" src="${img}" alt="logo">
</div>
`
}).join(""));
};
generateGallery();
the problem.
how can I make a function that display the pictures in modal when the user clicks on it? I tried different options but doesn't seem to work.
what I'm trying to achieve:
I need a function that will collect the images from this function, and it will display in modal when the user clicks on the image.

Related

Generating blog posts with html redirect via json backing file - javascript

I follow this tutorial ( https://www.youtube.com/watch?v=TlP5WIxVirU ) for using a search bar on my new blog and i apply the youtuber's advice and use his system of storing all my articles data into a json file.
All work perfectly but i tried to add a json variable into the href of my articles,
knowing that each of the href will be different, and it is impossible for me to make it work.
I tried a whole bunch of solutions found on the internet but it was impossible for me to redirect to each of the different article pages using the generation method via template.
The only way for me to achieve a redirect is to use this but the redirect only works on the first post :
<script>
var scrt_var = 10;
document.getElementById("link").setAttribute("href",scrt_var);
</script>
<a id="link"></a>
HMTL
<div class="divarticles" data-articles-container>
<template articles-template>
<a href="">
<div class="article">
<img class="imagearticle" data-imagearticle>
<div class="divtag">
<p class="tag" data-tag></p>
</div>
<p class="titlearticle" data-titre></p>
<p class="descriptionarticle" data-description></p>
<div class="auteur">
<img class="imgauteur" data-imageauteur>
<div class="textauteur">
<p class="nomauteur" data-auteur></p>
<p class="datearticle" data-datearticle></p>
</div>
</div>
</div>
</a>
</template>
</div>
JS
const articlesTemplate = document.querySelector("[articles-template]")
const articlesContainer = document.querySelector("[data-articles-container]")
const searchInput = document.querySelector("[data-search]")
let articles = []
searchInput.addEventListener("input", e => {
const value = e.target.value.toLowerCase()
articles.forEach(article => {
const isVisible =
article.name.toLowerCase().includes(value) ||
article.email.toLowerCase().includes(value)
article.element.classList.toggle("hide", !isVisible)
})
})
fetch("article.json")
.then(res => res.json())
.then(data => {
articles = data.map(article => {
const card = articlesTemplate.content.cloneNode(true).children[0]
const tag = card.querySelector("[data-tag]")
const titre = card.querySelector("[data-titre]")
const description = card.querySelector("[data-description]")
const auteur = card.querySelector("[data-auteur]")
const datearticle = card.querySelector("[data-datearticle]")
tag.textContent = article.tag
titre.textContent = article.titre
description.textContent = article.description
auteur.textContent = article.auteur
datearticle.textContent = article.datearticle
articlesContainer.append(card)
const imagearticlesrc = card.querySelector("[data-imagearticle]")
imagearticlesrc.src = article.image;
const imageauteursrc = card.querySelector("[data-imageauteur]")
imageauteursrc.src = article.auteurimage;
return { image: article.image, tag: article.tag, titre: article.titre, description: article.description, auteurimage: article.auteurimage, auteur: article.auteur, datearticle: article.datearticle, element: card }
})
})
JSON
[
{
"id": 1,
"image": "assets/image/articles/article1.jpg",
"tag": "Healthy",
"titre": "Titre de l'article article article article article",
"description": "Description description description description description descript ...",
"auteurimage": "assets/image/auteur.jpg",
"auteur": "Yftix",
"datearticle": "27/09/2030",
"pagearticle": "articles/article-banane.html"
},
{
"id": 2,
"image": "assets/image/articles/article1.jpg",
"tag": "Healthy",
"titre": "Titre de l'article article article article article",
"description": "Description description description description description descript ...",
"auteurimage": "assets/image/auteur.jpg",
"auteur": "Yftix",
"datearticle": "27/09/2030",
"pagearticle": "articles/article-banane.html"
}
]
Result
Result on website
After struggling for two days, I found the solution:
pagearticle.href = article.pagearticle

Get book properties of element on click in React

I have a map function outputting a list of books to my Books component. On each li that is being returned by the map function i have an onClick event handler that calls a function openBook, this function simply displays the info of that clicked book to a div on screen.
My issue is that for some reason, when i pass parameters to the openBook function it only passes the last li element's title and author and it seems to run the function without even me clicking on a book.
How can i pass the title and author params to the created div when i click on a particular book?
Here's my code and what i've tried.
Books.js
function Books() {
const {books} = useContext(BookContext) //{books} here is the array (API) with all books inside but as a state in the BookContext file
function openBook(title, author) {
const bookview = document.createElement('DIV')
if(document.body.contains(document.querySelector('.bookview'))) {
document.body.removeChild(document.querySelector('.bookview'))
}
bookview.innerHTML = '<i class="fas fa-times close"></i> <h4>'+info+'</h4>'
bookview.classList.add('bookview')
document.body.appendChild(bookview)
document.querySelector('.close').addEventListener('click', function() {
document.body.removeChild(document.querySelector('.bookview'))
})
}
return (
<>
<div className="bookshelf">
<ul>
{
books.map(book => {
return <li onClick={openBook(book.title, book.author)}>{book.title} <span>{book.author}</span><i class="fas fa-bookmark"></i></li>
})
}
</ul>
</div>
</>
)
}
BookContext (just has some books info)
const [books, setBooks] = useState([
{
id: 1,
title: "Digital Fortress",
author: "Dan Brown"
},
{
id: 2,
title: "Origin",
author: "Dan Brown"
},
{
id: 3,
title: "The Lord Of The Rings",
author: "J.R Tolkien"
},
{
id: 4,
title: "The Bourne Identity",
author: "Robert Ludlum"
}
])
You have to modify the onClick like this
<li onClick={() => openBook(book.title, book.author)}><span>{book.author}</span><i class="fas fa-bookmark"></i></li>
Because in the way you have returned the function would get executed onLoad itself and the return value will be assigned to onClick.
But what you actually require is a function that needs to be executed onClick of the li

Dropzone instance works on first element but not cloned elements (Vue)

I have a snippet below which is essentially my entire code block at this point, and essentially it creates a div and when you click "add another zone" it will clone that div. This allows the user to enter multiple lines of info and each have their own result and image.
The issue is that I'm successfully cloning everything with it's own unique identity thanks to my card setup. However, dropzone is not replicating. The first file dropzone form will work perfectly, but when I clone the div and have 2 or more dropzone insnstances on the page they don't work (they don't show the upload image text or anything)
How can I successfully apply my same logic to the dropzone instance here?
new Vue({
components: {},
el: "#commonNameDiv",
data() {
return {
searchString: [''],
results: [],
savedAttributes: [],
cards: [],
showList: false,
zoneNumber:[],
imageZoneNames: [] }
},
methods: {
autoComplete(ev, card) {
this.results = [];
console.log(this.searchString);
if (ev.target.value.length > 2) {
axios.get('/product/parts/components/search', {
params: {
searchString: ev.target.value
}
}).then(response => {
card.results = response.data;
this.showList = true;
console.log(this.results);
console.log(this.searchString);
});
}
},
saveAttribute(result, card) {
card.value = result.attribute_value;
card.results = [];
card.zone = this.zoneNumber;
this.showList = false;
},
addCard: function() {
this.cards.push({
index: "",
value: "",
zoneNumber: "",
results: [],
componentImage:""
});
console.log(this.cards);
},
hideDropdown() {
this.showList = false;
},
},
created() {
this.addCard();
let instance = this;
Dropzone.options = {
maxFilesize: 12,
renameFile: function (file) {
var dt = new Date();
var time = dt.getTime();
return time + file.name;
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
addRemoveLinks: true,
timeout: 50000,
removedfile: function (file) {
console.log(file.upload.filename);
var name = file.upload.filename;
var fileRef;
return (fileRef = file.previewElement) != null ?
fileRef.parentNode.removeChild(file.previewElement) : void 0;
},
init: function() {
this.on("addedfile",
function(file) {
instance.imageZoneNames.push({name: file.upload.filename, desc: 'Line Drawing'});
console.log(file);
console.log(instance.imageZoneNames);
});
}
};
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"> </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.5.0/dropzone.js"></script>
<div id="commonNameDiv">
<div class="uk-grid" v-for="(card, i) in cards" :key="i">
<div class="uk-width-1-10" >
<input v-model=" card.zoneNumber" size="4" type="text" name="mapNumber">
</div>
<div class="uk-width-6-10">
<input
style="width:100%"
placeholder="what are you looking for?"
v-model="card.value"
v-on:keyup="autoComplete($event, card)"
>
<div v-if="showList" class="panel-footer componentList" v-if="card.results.length">
<ul>
<li v-for="(result, i) in card.results" :key="i">
<a v-on:click="saveAttribute(result, card)">#{{ result.attribute_value }}</a>
</li>
</ul>
</div>
</div>
<div class="uk-width-3-10">
<form method="post" action="{{url('product/parts/upload/store')}}" enctype="multipart/form-data"
class="dropzone">
</form>
</div>
</div>
<div style="height: 35px;">
</div>
<div>
<a v-on:click="addCard">Add another zone</a>
</div>
</div>
When you instantiate the Dropzone class, it automatically looks for elements to transform in dropzones (by default, elements with the .dropzone class).
It looks like you want to dynamically add elements that are dropzones. Then you need to trigger the dropzone transformation yourself.
I would suggest you disable the autoDiscover option, and manually designates each element you want to transform into dropzones :
addCard() {
this.cards.push({
...
});
let cardIndex = this.cards.length - 1;
// Waiting for the element #dropzone-X to exist in DOM
Vue.nextTick(function () {
new Dropzone("#dropzone-"+cardIndex, {
...
});
});
},
created() {
...
Dropzone.autoDiscover = false
// no new Dropzone()
...
// Starting setup
this.addCard();
},
<form ... class="dropzone" v-bind:id="'dropzone-'+i">
Working jsbin
There are several ways to select the element to transform ($refs, ids, classes), here I'm suggesting ids.
See the doc on programmatically creating dropzones
Actually it is being created, but the Dropzone is not being reconstructed.
I think you have to create a new instance of the Dropzone.
if you try to insert:
created() {
this.addCard();
var myDropzone = new Dropzone('.dropzone')
let instance = this;
Dropzone.options.myDropzone = {
or even add the options to the addCard method or set a setupDropzones method and add it to the addCard method.

Javascript load more images of the array onclick. Using Firebase

I'm trying to make my website a little bit faster, and for that, I'm trying to make a button that on each click presents more images. For example: a user can see 5 images, and if the user wants to see 5 more he can, by clicking on the button.
So for now only got this, and i really think it's not the right way.
HTML ->
<ion-card *ngFor="let pic of photoList">
<h1>{{pic?.username}}</h1>
<h2>{{pic?.name}}</h2>
<img src={{pic?.picture}}>
</ion-card>
<button ion-button (click)="load()">Load More Images</button>
Js ->
load() {
firebase.database().ref('HomeList').limitToLast(5).on('value', snapshot => {
this.photoList = [];
snapshot.forEach(snap => {
this.photoList.push({
id: snap.key,
name: snap.val().name,
username: snap.val().username,
picture: snap.val().picture,
email: snap.val().email,
uid: snap.val().uid,
rating: snap.val().rating
});
console.log(this.photoList);
return false
});
return this.photoList.reverse();
});
}
so you need a pagination try to use .startAfter(number) and .limit(number); assuming this.current = 0; sets in constructor();
load() {
firebase.database().ref('HomeList').startAfter(this.current).limit(5).on('value', snapshot => {
this.photoList = [];
snapshot.forEach(snap => {
this.photoList.push({
id: snap.key,
name: snap.val().name,
username: snap.val().username,
picture: snap.val().picture,
email: snap.val().email,
uid: snap.val().uid,
rating: snap.val().rating
});
console.log(this.photoList);
this.current = this.current + photoList.length;
return false
});
return this.photoList.reverse();
});
}

Javascript to pass information to HTML

I have a main page and there are items on the page. When I click "Order Now" on an item, an HTML page slides in over a portion of the page to show the item's details. I am having trouble linking the item clicked with an item inside an array of objects containing the details for each item so I can show the details on the page that slides over.
Here's the main page:
<div class="col-md-4 col-sm-6">
<div class="shop-item">
<div class="shop-thumbnail">
<img src="img/originalImage.jpg" alt="">
</div>
<div class="shop-item-footer">
<div class="shop-item-details">
<h3 class="shop-item-title">Original Title</h3>
<span class="shop-item-price">
$50.00
</span>
</div>
<div class="shop-item-order-btn">
Order Now
</div>
</div>
</div>
</div>
The page slides over fine, but I can't seem to get the image to change. The html file that has the info that slides out onto the screen is all encompassed into an article tag. Here's the top snippet of the HTML with the image that I can't seem to get to change.
<article class="order-details">
<div class="order-totals">
<div class="product-image">
<!-- ID for image -->
<img id="pageOrder" src="../img/Image1.jpg" alt="">
</div>
</div>
</article>
This is my JS so far that's not working.
var items = [{ name: 'Black', cost: '$10.00', id: '001', src: '../img/Black.jpg' }, { name: 'Something', cost: '$10.00', id: '002', src: '../img/image2.jpg' },
function changeImage() {
for (var i = 0; i >= items.count; i++) {
if (i = items.count) {
document.getElementById('pageOrder').src = items.src;
}
}
};
If I understand you correctly, when you click the order button, you can find the item by id in items by reading the data-id property on the order button that was clicked and then access the properties from that item like so:
To get this working with your specific scenario, you will have to modify some functions that you did not include in your original question, but I dug up from the link you provided in the comments. The code would look like the following:
var items = [{
name: 'Black',
cost: '50.00',
id: '001',
src: 'img/Black2.jpg'
}, {
name: 'Red',
cost: '50.00',
id: '002',
src: 'img/BloodRed2.jpg'
}, {
name: 'Desert Fox',
cost: '50.00',
id: '003',
src: 'img/DesertFox.jpg'
}];
// Single Post via Ajax
//------------------------------------------------------------------------------
var ajaxLoadLink = $('.ajax-load-link'),
orderBackdrop = $('.order-content-backdrop'),
orderContainer = $('.order-content-wrap'),
orderContentWrap = $('.order-content-wrap .inner'),
orderContent = $('.order-content-wrap .inner .order-content'),
closeBtn = $('.order-content-wrap .close-btn'),
orderPreloader = $('.order-content-wrap .preloader');
// Open Order
function openOrder(itemDetails) {
$('body').addClass('order-content-open');
orderBackdrop.addClass('active');
orderContainer.addClass('open');
orderPreloader.addClass('active');
orderContentWrap.addClass("loaded");
setTimeout(function() {
orderPreloader.removeClass('active');
// insert data from itemDetails into their respective places on the form
$(".order-content-wrap .order-details .product-image img").attr("src", itemDetails.src);
$(".order-content-wrap .order-details .product-image img").attr("alt", itemDetails.name);
$(".order-content-wrap .product-title").text(itemDetails.name);
$(".order-content-wrap .price i").text(itemDetails.cost);
$(".order-content-wrap .total-cost i").text(itemDetails.cost);
}, 900);
}
// Close Order
function closeOrder() {
$('body').removeClass('order-content-open');
orderBackdrop.removeClass('active');
orderContainer.removeClass('open');
orderContentWrap.removeClass('loaded');
}
ajaxLoadLink.on('click', function(e) {
var itemDetails = items.find(item => item.id === $(this).attr('data-id'));
openOrder(itemDetails);
e.preventDefault();
});
Working Demo
Code is too long to put in a stack snippet
Make sure to press "Run with JS" when you load the jsbin

Categories