Dynamically changing the Image source for HTML,JSON - javascript

I have been trying to make some CSS cards using JSON data from Firebase database. Main idea is using the data from Firebase, I am trying to build CSS cards for each submission from a form.
During form submission, User chooses which category it belongs to and specific Image should be displayed in CSS card.
As the CSS cards are dynamically created, the entire HTML code is built using JS.
First this is the code for fetching data from Firebase and calling the function to create the CSS card.
let reference = firebase.database().ref("data-block");
reference.on("value",gotData);
Now check the function for creating the CSS card.
function gotData(data) {
let x = data.val();
let keys = Object.keys(x);
console.log(keys.length);
var q = 0;
for (let i = 0; i < keys.length; i++) {
let a = keys[i];
let title_a = expens[a].Entry;
let category_a = expens[a].Category;
console.log(title_a, category_a);
let expense = document.querySelector(".card-list");
expense.innerHTML += `
<article class="card">
<header class="card-header">
<h2>${title_a} </h2>
</header>
<div class="card-author">
<a class="author-avatar" href="#">
<img id="x" src=""/>
</a>
<svg class="half-circle" viewBox="0 0 106 57">
<path d="M102 4c0 27.1-21.9 49-49 49S4 31.1 4 4"></path>
</svg>
<div class="author-name">
<div class="author-name-prefix">Author</div>
${category_a}
</div>
</article>
`;
}
}
As you can see src of the image is not declared because I couldn't figure out how to assign different images based on Category fetched from Database
I have 3 images like
shopping.png
food.png
learn.png
Help me out on how to assign src for the image tag dynamically based on data from Firebase.

function getImageByCategory(category) {
if (category == 'shopping') {
return '<img src="shopping.png" />';
} else if (category == 'food') {
return '<img src="food.png" />'
} else if (category == 'learn') {
return '<img src="learn.png" />'
}
}
`
<a class="author-avatar" href="#">
${getImageCategory(category_a)}
</a>

Assuming you know the values of the categories you could create an object that will translate those category values into the image names.
Try this (changing categoryA, categoryB, and categoryC into the values being returned as category_a):
...
let category_a=expens[a].Category;
const IMAGE {
categoryA: 'shopping.png',
categoryB: 'food.png'.
categoryC: 'learn.png'
}
console.log(title_a,category_a);
let expense=document.querySelector(".card-list");
expense.innerHTML+= `
<article class="card">
<header class="card-header">
<h2>${title_a} </h2>
</header>
<div class="card-author">
<a class="author-avatar" href="#">
<img id="x" src=${IMAGE[category_a]}/>
</a>
...

Related

How to add html data to local storage and have it appear on a seperate html page

I have had trouble with a movie watch list project where i have two main pages (movie search page and watch list page) and one JS file they both share. I would like to be able to save a movie result after having searched for a movie on the first HTML page, and have it save to local storage and appear on the second HTML page.
I was able to create a watch list that lives on the same page as the movie search page and save selections temporarily, but when I refresh they disappeared. When I have tried saving to a separate page, I am unable to first fetch the ID where I want to insert the HTML data. I kind of understand this is because I am only able to load one page at at time, yet I have been unable to figure out what to do about it. I have also tried to use preventDefault to stop my second HTML page from refreshing in order to see if my data is saving, but i have been unsuccessful in this as well.
Here is my java script document which both pages share
function run(){
let ID
let movArr
document.querySelector("#search").addEventListener('click',async function(){
const movSearch = document.querySelector("#movieSearch").value
const res = await fetch(`https://www.omdbapi.com/?s=${movSearch}&type=Movie&apikey=3c746e2`)
const data = await res.json()
movArr = data.Search
html=""
for(let movie of movArr)
{
const rez = await fetch(`https://www.omdbapi.com/?i=${movie.imdbID}&type=Movie&apikey=3c746e2`)
const datatwo = await rez.json()
ID = datatwo.imdbID
html +=
` <div class="movieInput" style="display:flex;align-items:center">
<div>
<img src="${movie.Poster}" style="width:99px;margin:42px 0 0 44px">
</div>
<div></div>
<div style="margin:3px 0 0 21px">
<text style="font-weight:bold; font-size:18px">${movie.Title}</text>
<p>${datatwo.imdbRating}</p>
<div style="display:flex; gap:36px; font-size:12px">
<p>${datatwo.Runtime}</p> <p>${datatwo.Genre}</p> <p><i class="fa-solid fa-circle-plus" data-add="${datatwo.imdbID}"></i></p>
</div>
<div style="margin:-20px 0 0 0">
<p>${datatwo.Plot}</p>
</div>
</div>
</div>
<hr />`}
document.querySelector("#movies").innerHTML = html
}) }
function watchlist(){
localStorage.setItem( 'film' , JSON.stringify(html) )
document.querySelector('#moviesToo').innerHTML = JSON.parse(localStorage.getItem('film'))
}
function watch(){
let html
document.addEventListener('click', async function(e){
if(e.target.dataset.add){
console.log('clicked!')
const movie = e.target.dataset.add
const dez = await fetch(`https://www.omdbapi.com/?i=${movie}&type=Movie&apikey=3c746e2`)
const datathree = await dez.json()
ID = datathree.imdbID
html =
`
<div class="movieInput" style="display:flex;align-items:center">
<div>
<img src="${datathree.Poster}" style="width:99px;margin:42px 0 0 44px">
</div>
<div></div>
<div style="margin:3px 0 0 21px">
<text style="font-weight:bold; font-size:18px">${datathree.Title}</text>
<p>${datathree.imdbRating}</p>
<div style="display:flex; gap:36px; font-size:12px">
<p>${datathree.Runtime}</p> <p>${datathree.Genre}</p> <p><i class="fa-solid fa-circle-minus" data-add="${datathree.imdbID}"></i></p>
</div>
<div style="margin:-20px 0 0 0">
<p>${datathree.Plot}</p>
</div>
</div>
</div>
<hr />`}
return watchlist()
})
}
run()
watch()

JavaScript filter loop control. How can I handle every single element?

The problem is I can't control the filter remember I have 20 products I need to establish if my category is not matched else product not found.
But my code product not found returned 20 times 🤨
see my output Screenshot
html = `<p>Product not found</p>` // just + sign remove
I am trying another way it returns a single time but, if my condition is true the product does not show like
`if (post.category === "men's clothing")`
How can I solve it?
// Men catagory
men.addEventListener('click', loadDataMen);
function loadDataMen() {
fetch('./src/db/db.json')
.then(function (response) {
return response.json();
})
.then(function (info) {
let html = '';
info.filter((post) => {
try {
if (post.category === "no match") {
html += `
<div class="single_product product-box bg-darkopacity rounded-20 position-relative mb-5 grid_view p-3">
<!--
Hover Zoom you can cancel if you don't like it just remove "hover-zoom" class
-->
<div class="hover-zoom drop-shadow-product position-relative">
<!-- PLaceholder Image -->
<img src="${post.image}" alt="Image" />
<!-- User Rating -->
<div class="show-rating">
<div class="rate">
${post.rating.rate} ⭐ | ${post.rating.count}
</div>
</div>
</div>
<!-- Product Wishlist -->
<div class="love bubbly-button">
<i class="fa-regular fa-heart"></i>
</div>
<!-- Product Offer -->
<div class="product-tag-warning badge bg-warning">${post.tag}</div>
<div class="product-functionality text-center mt-3">
<!-- Product title -->
<div class="product-title fw-bold text-break">
${post.title.substring(0, 18)}...
</div>
<!-- Product price -->
<div class="product-price mb-2"><strong>${post.price} only</strong></div>
<!-- Router navigation -->
<div class="two-btn-sm">
View
Buy
</div>
</div>
<!-- Product Description -->
<div class="discription">
<small class="text-decoration-underline">
<strong>Discription</strong>
</small>
<p class="p-0">
${post.description} SeeMore
</p>
</div>
</div>
`;
}
else{
html += `<p>Product not found</p>`
}
} catch (error) {
html = `<p>Somthing went wrong ${error}</p>`
}
})
output.innerHTML = html
})
.catch(function (error) {
console.log(error)
})
}
The problem is that you are using the filter method as a loop.
For more info about filter method check this out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
You must filter your posts result using a condition like so:
let filteredPosts=info.filter((post)=>post.category === "no match");
then doing something like that:
if(filteredPosts.length<=0){
html='Product not found'
}else{
filteredPosts.splice(4); //only 4 posts
for(let post of filteredPosts){
html+=....
}
}
Improved response:
What you have to do to filter by category or color or both, you must save which category and color the user has selected:
let selectedCategory=null;
let selectedColor=null;
let categoryItems=document.getElementByClassName('category'); //assuming categories items has a class category
for(let categoryItem of categoryItems){
//foreach category found
categoryItem.addEventListener('click', function(event){
selectedCatory=this.innerHTML; //get the clicked category
showFilteredItems();
});
}
let colorsItems=document.getElementByClassName('color');
//assuming colors items has a class color
for(let colorItem of colorsItems){
//foreach color found
categoryItem.addEventListener('click', function(event){
selectedColor=this.innerHTML; //get the clicked color
showFilteredItems();
});
}
//this function is your old method
function showFilteredItems(){
....
fetch(...)
....
//by default all results
let filteredPosts=info;
//category filter
if(selectedCategory){
filteredPosts=filteredPosts.filter((post)=>post.category === selectedCategory);
}
//color filter
if(selectedColor){
filteredPosts=filteredPosts.filter((post)=>post.color=== selectedColor);
}
//show the items
if(filteredPosts.length<=0){
html='Product not found'
}else{
filteredPosts.splice(4); //only 4 posts
for(let post of filteredPosts){
html+=....
}
}
}
Keep in mind that in production application, we prefer to send filters(category and color) to the backend of the application that way you will not receive all the items (this can be really slow if you have thousands of items) but only the filtered.

Problems getting data from Firestore to display in DOM

I'm creating a project with the use of Firebase and I'm having some issues with getting the data inside of my database to display in the DOM due to error "setupFoodGroup is not defined"...This is likely due to a rookie coding error, but I can't seem to work out where I've gone wrong.
Current code as per below:
// Get data from database
db.collection('foodgroups').get().then(snapshot => {
setupFoodGroup(snapshot.docs);
});
// Setting Up Food Lists
const foodList = document.querySelector('.foodGroups');
const setupFoodGroup = (data) => {
let html = '';
data.forEach(doc => {
const group = doc.data();
const li = `
<li>
<div class="card bg-light mb-3" style="max-width: 20rem;">
<div class="card-body">
<h4 class="card-title">${group.title}</h4>
<p class="card-text">${group.content}</p>
</>
</div>
</li>
`;
html += li
})
foodGroups.innerHTML = html;
};
I'm then wanting to get them displaying inside the following HTML on a display page
<div class="card-body">
<ul class="foodGroups">
</ul>
</div>
Any points would be very much appreciated.
Cheers!

How to filter an image gallery using url parameters

I'm creating a commerce site for my portfolio and I have a page with gallery of product cards that I would like to add filters for. The cards were generated dynamically using a json file.
I can figure this out using just javascript and CSS but in reviewing other sites I noticed that then you trigger their filters, parameters are appended to or removed from the url.
Here's my javascript for this page. As you can see I already use a function that takes you to an individual item by appending to the url, but I can't figure out how this is done for filters.
// ========== Load Gallery Images ========================================
$.getJSON("../../json/guitars.json", function(data) {
var guitar_data = '';
for(var i in data) {
// data
var image1 = data[i].img1
var alt = data[i].alt
var title = data[i].title // use for sort-by
var price = data[i].price
// filters
var id = data[i].product_id
var category = data[i].category
var brand = data[i].brand
var condition = data[i].condition
guitar_data += '<div class="gallery-card">'
guitar_data += `<img class="more-info img-fluid" src="../${image1}" alt="${alt}">`
guitar_data += `<h6>${title}</h6>`
guitar_data += `<p><strong>${price}</strong></p>`
guitar_data += '</div>'
}
$('#img-gallery').html(guitar_data)
})
// ========== Load Gallery Images End ====================================
$(document).ready(function() {
// ======== More Info ==================================================
$(".more-info").on("click", function(e) {
const product_id = $(e.target).attr('product_id')
$.getJSON("../../json/guitars.json", function(json) {
for(let i in json) {
if (product_id === json[i].product_id ) {
window.location.href = "./product.html?product=" + product_id
}
}
})
})
// ======== More Info End ===============================================
Here is one of my filters
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordionExample">
<div class="card-body" style="border:none;">
<ul style="list-style:none;padding-left:5px;">
<li>
<input type="checkbox" name="brand" value="fender">
<label style="padding-left:10px;" for="">Fender</label>
</li>
<li>
<input type="checkbox" name="brand" value="gibson">
<label style="padding-left:10px;" for="">Gibson</label>
</li>
<li>
<input type="checkbox" name="brand" value="gretsch">
<label style="padding-left:10px;" for="">Gretsch</label>
</li>
</ul>
</div>
</div>
I'm not asking for anyone for code, but rather direction. I'm a bit lost at the moment.
You can wrap the related html layout in a FORM with method="GET", and you call form's submit() at every filter click.
In this way every selected field would update the URL parameters i.e. querystring.

Repeat div tags in specific number of sets from angularjs in html code

I have the following div tag which I want to repeat multiple times
<div class="item">
<div class="col-xs-3 " style="margin-right:-50px;" ng-repeat="(key, value) in products.slice(4, 8) track by $index">
<img src= {{value.imageUrl}} alt="No Image"/>
</div>
</div>
I want repeat the above entire div tag multiple times where each div tag displays 4 images at a time i.e the next div tag will have ng-repeat="(key, value) in products.slice(8, 12) track by $index" and so on till there are images in the value object. How can this be achieved using angularjs?
Appreciate your help. Thanks in advance.
I think you should prepare the data better in the controller that's providing the products array. You could probably do this all inline but my guess is it would be pretty nasty.
Here's my suggestion.
The bottom code would provide you with arrays each with four entries of your images. You could change that by modifying the count variable and the reset inide the loop.
ExampleController.js
'use strict';
app.controller('ExampleCtrl', function ($scope) {
var products = [
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'},
{'name':'Test','url':'some_image.jpg'}
];
var products_page = [];
var products_pages = [];
var count = 4;
$scope.products_pages = products_pages;
for(var i=0;i<products.length;i++){
if(count > 1){
products_page.push(products[i]);
count--;
if(products.length === i+1){
products_pages.push(products_page);
return;
}
}else{
products_page.push(products[i]);
products_pages.push(products_page);
products_page = [];
count = 4;
}
}
});
Now with this out of the way you could do the following in the HTML.
<div class="item" ng-repeat="page in products_pages">
<div class="col-xs-3 " style="margin-right:-50px;" ng-repeat="image in page">
<img src= {{image.url}} alt="No Image" />
</div>
</div>
Haven't tested it but I think this should do the trick. If you need it to be all inline, somebody else will have to pitch in.

Categories

Resources