Retrieve and display data using Javascript and Firebase Firestore - javascript

No matter what I do, I'm unable to display my data. In my HTML I've set up this empty list:
<div class="reviews" style="margin-top: 40px;">
<ul id="reviews-list"></ul>
</div>
And this is what I have for JS:
// load
const querySnapshot = await getDocs(collection(db, "reviews"));
querySnapshot.forEach((doc) => {
createFormData(doc);
})
const formData = document.querySelector('.reviews');
function createFormData(doc) {
let div = document.createElement('DIV');
let title = document.createElement('span');
let hall = document.createElement('span');
let content = document.createElement('span');
title.textContent = doc.data().title;
hall.textContent = doc.data().hall;
content.textContent = doc.data().content;
div.appendChild(title);
div.appendChild(hall);
div.appendChild(content);
formData.appendChild(div);
}
Can anyone help?
I tried multiple Youtube videos and other sources to display my database data in a ul, and it either gives errors or nothing happens.

try this
const formData = document.querySelector('.reviews');
createFormData()
async function createFormData() {
const querySnapshot = await getDocs(collection(db, "reviews"));
querySnapshot.forEach((doc) => {
const div = document.createElement('DIV');
const title = document.createElement('span');
const hall = document.createElement('span');
const content = document.createElement('span');
title.textContent = doc.data().title;
hall.textContent = doc.data().hall;
content.textContent = doc.data().content;
div.appendChild(title);
div.appendChild(hall);
div.appendChild(content);
formData.appendChild(div);
})
}

Related

How to achieve individual card functionality with JS?

Repo: https://github.com/bigolboyyo/weatherdbapp
Hello! I am working on a small project working with an API for the first time. I'm making a simple weather app that allows you to type in a location and append a "card" of data.
This card has a "front" and "back". Front being the weather data and the back being a simple textarea notepad.
As far as functionality goes I am just about there. My only issue is now when I have more than one card I only get an event listener on the first card button and the first card's button affects all the other cards created after! How would I apply the event listener for each card's buttons made and have those buttons only affect the relevant card?
Current code I'm working with
let notesBtn = document.getElementById("notes-btn");
notesBtn.addEventListener("click", handleFrontClick);
console.log(notesBtn);
function handleFrontClick(e) {
e.target.parentNode.remove();
card.appendChild(back);
let frontBtn = document.getElementById("front-btn");
frontBtn.addEventListener("click", (e) => {
e.target.parentNode.remove();
card.appendChild(front);
});
ALL JS (git repo above)
const body = document.getElementsByTagName("body");
const unsplashRandom =
"https://source.unsplash.com/random/1920x1080/?landscapes";
document.body.style.backgroundImage = `url(${unsplashRandom})`;
const header = document.createElement("div");
header.className = "header";
header.id = "header";
document.body.append(header);
const container = document.createElement("div");
container.className = "container";
document.body.append(container);
const h1 = document.createElement("h1");
h1.id = "h1";
h1.textContent = "WeatherDB Search";
h1.style.textAlign = "center";
header.append(h1);
let p1 = document.createElement("p");
p1.id = "p1";
p1.textContent = "Enter location for today's weather!";
p1.style.textAlign = "center";
header.append(p1);
const cityInput = document.createElement("input");
cityInput.className = "search-inputs";
cityInput.id = "city-input";
cityInput.placeholder = " ex: New York, Toronto, London";
header.append(cityInput);
const searchButton = document.createElement("button");
searchButton.className = "buttons";
searchButton.id = "search-btn";
searchButton.textContent = "🔍";
let br = document.createElement("br");
header.append(br);
header.append(searchButton);
function fetchWeather(e) {
let userInput = cityInput.value;
let config = {
Headers: {
"Content-type": "application/json",
},
};
return fetch(
`https://weatherdbi.herokuapp.com/data/weather/${userInput}`,
config
)
.then((res) => res.json())
.then((json) => weatherSearch(json, userInput))
.catch((err) => {
window.alert(
`${err} \n https://weatherdbi.herokuapp.com/data/weather/${userInput}`
);
console.log(err);
});
}
function weatherSearch(e, userInput) {
cityInput.value = "";
let weatherKeys = Object.keys(e.currentConditions);
let weatherValues = Object.values(e.currentConditions);
let temps = Object.values(weatherValues[1]);
let speeds = Object.values(weatherValues[4]);
const card = document.createElement("div");
card.id = `${userInput}-card`;
card.className = "cards";
container.append(card);
const front = document.createElement("div");
front.id = `${userInput}-front`;
front.className = "front";
front.innerHTML = `
<h1>${userInput.toUpperCase()}</h1>
<p>Time: ${weatherValues[0]}</p>
<li id="comment">Comment: ${weatherValues[6]}</li>
<li id="precipitation">Precipitation: ${weatherValues[2]}
<li id="temp">Temp: ${temps[0]}c | ${temps[1]}f</li>
<li id="humidity">Humidity: ${weatherValues[3]}</li>
<li id="wind">Wind Speed: ${speeds[0]}km | ${speeds[1]}mile</li>
</br>
<button id="notes-btn" class="buttons">Notes</button>
`;
card.append(front);
const back = document.createElement("div");
back.id = `${userInput}-back`;
back.className = "back";
back.innerHTML = `
<textarea id="back-text" name="backtext"
rows="25" placeholder="NotePad">
</textarea>
</br>
<button id="front-btn">Flip</button>
`;
let notesBtn = document.getElementById("notes-btn");
notesBtn.addEventListener("click", handleFrontClick);
console.log(notesBtn);
function handleFrontClick(e) {
e.target.parentNode.remove();
card.appendChild(back);
let frontBtn = document.getElementById("front-btn");
frontBtn.addEventListener("click", (e) => {
e.target.parentNode.remove();
card.appendChild(front);
});
}
}
document.addEventListener("DOMContentLoaded", (e) => {
searchButton.addEventListener("click", (e) => {
fetchWeather();
});
document.addEventListener("keydown", function (e) {
if (e.key === "Enter" && cityInput.value.length > 0) {
fetchWeather();
}
});
});

Remove previous DOM elements when using array map method

I'm trying to implement server side pagination with NodeJS/Express. But the frontend rendering of it isn't working as expected. I fetch from a third-party API and implement the logic for the pagination. I then connect it to the frontend for rendering.
I have created cards to render the information from the API, first time remove the cards to render next page elements/cards with the code:
if(card !== undefined){
card.remove();
}
It works and it removes the cards, you can see this in the frontend, first eventlistener. But when I try to implement the same in the second eventlistener the elements/cards aren't removed and replaced with new ones.
Pagination - Backend
const express = require('express');
const router = express.Router();
const fetch = require('node-fetch');
router.get('/pokemon', function(req, res) {
async function getPokemonInfo(){
return fetch('https://pokeapi.co/api/v2/pokemon?limit=251')
.then(response => response.json())
.then(data => {
getDetailsPokemon(data)
}).catch(error => {
console.log(error);
})
}
getPokemonInfo()
async function getDetailsPokemon(pokemon){
const pokemonArr = pokemon.results;
const eachPokemon = pokemonArr.map(pokeEl => {
return fetch(pokeEl.url)
.then(response => response.json())
.catch(error => {
console.log(error);
})
})
Promise.all(eachPokemon)
.then(values => {
const page = parseInt(req.query.page);
const limit = parseInt(req.query.limit);
console.log(page, limit);
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
console.log(startIndex, endIndex);
const results = {}
if(endIndex < values.length){
results.next = {
page: page + 1,
limit: limit
}
}
if(startIndex > 0){
results.previous = {
page: page - 1,
limit: limit
}
}
results.result = values.slice(startIndex, endIndex);
console.log(results);
res.json(results)
})
}
})
module.exports = router;
Pagination - Frontend
const paginatedApp = {
paginatedPokemon: async function(){
await fetch(`http://localhost:1337/pokemon?page=1&limit=20`)
.then(response => response.json())
.then(data => {
this.createCards(data)
})
},
createCards: function(pokemonObj){
let next = document.querySelector('.next');
let previous = document.querySelector('.previous');
pokemonObj.result.map(pokeEl => {
// Variables
let main = document.querySelector('main');
let card = document.createElement('div');
let imgHolder = document.createElement('div');
let img = document.createElement('img');
let infoHolder = document.createElement('div');
let infoBoxOne = document.createElement('div');
let infoBoxTwo = document.createElement('div');
let pId = document.createElement('p');
let pName = document.createElement('p');
let boxForType = document.createElement('div');
let id = document.createTextNode('id:');
let name = document.createTextNode('name:');
let type = document.createTextNode('type:');
// Info box 1
let infoPId = document.createElement('p');
let infoPName = document.createElement('p');
let infoPType = document.createElement('p');
infoPId.append(id);
infoPName.append(name);
infoPType.append(type);
infoBoxOne.append(infoPId, infoPName, infoPType);
infoBoxTwo.append(pId, pName, boxForType);
// Lägg till klasser
card.classList.add('card');
imgHolder.classList.add('imgHolder');
infoHolder.classList.add('infoHolder');
boxForType.classList.add('boxForType');
img.classList.add('img');
infoHolder.classList.add('infoHolder');
pId.classList.add('id');
pName.classList.add('name');
infoBoxOne.classList.add('infoBoxOne');
infoBoxTwo.classList.add('infoBoxTwo');
img.src = pokeEl.sprites.other['official-artwork']['front_default'];
pId.append(`#${pokeEl.id}`);
pName.append(pokeEl.name);
// Types
pokeEl.types.map(pokeType => {
let pokemonType = pokeType.type.name
let pokes = document.createElement('p');
pokes.append(pokemonType)
boxForType.append(pokes);
})
imgHolder.appendChild(img);
card.appendChild(imgHolder)
main.appendChild(card);
infoHolder.append(infoBoxOne)
infoHolder.append(infoBoxTwo)
card.appendChild(infoHolder);
boxForType.children[0].style.border = '1px solid #fff';
boxForType.children[1] ? boxForType.children[1].style.border = '1px solid #fff' : console.log('boxForType.children[1] dosen\'t exist for this post');
next.addEventListener('click', () => {
if(card !== undefined){
card.remove();
}
})
})
// Second next eventlistener
next.addEventListener('click', () => {
fetch(`http://localhost:1337/pokemon?page=${pokemonObj.next.page++}&limit=20`)
.then(response => response.json())
.then(data => {
data.result.map(dataEl => {
let main = document.querySelector('main');
let card = document.createElement('div');
if(card !== undefined){
card.remove();
}
let imgHolder = document.createElement('div');
let img = document.createElement('img');
let infoHolder = document.createElement('div');
let infoBoxOne = document.createElement('div');
let infoBoxTwo = document.createElement('div');
let pId = document.createElement('p');
let pName = document.createElement('p');
let boxForType = document.createElement('div');
let id = document.createTextNode('id:');
let name = document.createTextNode('name:');
let type = document.createTextNode('type:');
// Info box 1
let infoPId = document.createElement('p');
let infoPName = document.createElement('p');
let infoPType = document.createElement('p');
infoPId.append(id);
infoPName.append(name);
infoPType.append(type);
infoBoxOne.append(infoPId, infoPName, infoPType);
infoBoxTwo.append(pId, pName, boxForType);
// Lägg till klasser
card.classList.add('card');
imgHolder.classList.add('imgHolder');
infoHolder.classList.add('infoHolder');
boxForType.classList.add('boxForType');
img.classList.add('img');
infoHolder.classList.add('infoHolder');
pId.classList.add('id');
pName.classList.add('name');
infoBoxOne.classList.add('infoBoxOne');
infoBoxTwo.classList.add('infoBoxTwo');
img.src = dataEl.sprites.other['official-artwork']['front_default'];
pId.append(`#${dataEl.id}`);
pName.append(dataEl.name);
// Types
dataEl.types.map(pokeType => {
let pokemonType = pokeType.type.name
let pokes = document.createElement('p');
pokes.append(pokemonType)
boxForType.append(pokes);
})
imgHolder.appendChild(img);
card.appendChild(imgHolder)
main.appendChild(card);
infoHolder.append(infoBoxOne)
infoHolder.append(infoBoxTwo)
card.appendChild(infoHolder);
if(card !== undefined){
card.remove();
}
})
})
})
}
}
paginatedApp.paginatedPokemon();

How to display images and embed in the transcript file?

I'm making a ticket bot where a user creates a ticket and then gets the support they need then after an admin or the same user closes the ticket a transcript will be saved and sent in the same channel and I've already done that but the only thing I'm struggling at is displaying Embeds and Images in that transcript log. Now it looks like this (Copy paste it to see):
file:///G:/BotTickets/Akeoe%20792817221239832627.html
I figured maybe the image would help you understand more, all the bots( ASOG ) messages is Embeds and it looks like that with images too
Code of how I save and display:
let messageCollection = new Discord.Collection();
let channelMessages = await channel.messages.fetch({
limit: 100
}).catch(err => console.log(err));
messageCollection = messageCollection.concat(channelMessages);
while(channelMessages.size === 100)
{
let lastMessageId = channelMessages.lastKey();
channelMessages = await channel.messages.fetch()({ limit: 100, before: lastMessageId }).catch(err => console.log(err));
if(channelMessages)
messageCollection = messageCollection.concat(channelMessages);
}
let msgs = messageCollection.array().reverse();
let data = await fs.readFile('./commands/template.html', 'utf8').catch(err => console.log(err));
if(data)
{
await fs.writeFile(`G:\BotTickets/${ticketUserusername + ` ` + channel.id}.html`, data).catch(err => console.log(err));
let guildElement = document.createElement('div');
let guildText = document.createTextNode(message.guild.name);
let guildImg = document.createElement('img');
guildImg.setAttribute('src', message.guild.iconURL());
guildImg.setAttribute('width', '150');
guildElement.appendChild(guildImg);
guildElement.appendChild(guildText);
console.log(guildElement.outerHTML);
await fs.appendFile(`G:\BotTickets/${ticketUserusername + ` ` + channel.id}.html`,
guildElement.outerHTML).catch(err => console.log(err));
msgs.forEach(async msg => {
let parentContainer = document.createElement("div");
parentContainer.className = "parent-container";
let avatarDiv = document.createElement("div");
avatarDiv.className = "avatar-container";
let img = document.createElement('img');
img.setAttribute('src', msg.author.displayAvatarURL());
img.className = "avatar";
avatarDiv.appendChild(img);
parentContainer.appendChild(avatarDiv);
let messageContainer = document.createElement('div');
messageContainer.className = "message-container";
let nameElement = document.createElement("span");
let name = document.createTextNode(msg.author.tag + " " + msg.createdAt.toDateString() + " " +
msg.createdAt.toLocaleTimeString() + " EST");
nameElement.appendChild(name);
messageContainer.append(nameElement);
if(msg.content.startsWith("```"))
{
let m = msg.content.replace(/```/g, "");
let codeNode = document.createElement("code");
let textNode = document.createTextNode(m);
codeNode.appendChild(textNode);
messageContainer.appendChild(codeNode);
}
else
{
let msgNode = document.createElement('span');
let textNode = document.createTextNode(msg.content);
msgNode.append(textNode);
messageContainer.appendChild(msgNode);
}
parentContainer.appendChild(messageContainer);
await fs.appendFile(`G:\BotTickets/${ticketUserusername + ` ` + channel.id}.html`,
parentContainer.outerHTML).catch(err => console.log(err));
});
}

How do I Convert a HTML Collection into an array, without emptying it? #2

I am trying to convert an HTML Collection of "li"s into an array, but the result in the array being emptied.
I read this question and applied that, but it doesn't work.How do I convert a HTMLCollection into an array, without emptying it?
<body>
<ul id="base"></ul>
<script>
const json = [{
"id" : "1",
"date" : "2013/05/05",
},{
"id" : "2",
"date" : "2019/05/05",
}];
for (item of json) {
const list = document.createElement('li');
list.textContent = `${item.date}`;
base.appendChild(list)
}
///the code above works fine.
const base = document.getElementById("base");
const myNodeList = base.getElementsByTagName("li");
console.log(myNodeList);
// gives HTMLCollection
const myArray = Array.from(myNodeList)
// returns empty array
</script>
</body>
the result
I tested the same code on console and it worked fine as below.
The code cannot work before you are using base before initializing it. Placing the initialization before using it makes it work.
Here I modified it: https://jsfiddle.net/tk78z5gq/
Thank you so much guys!
The problem was async.
I should have said that earlier, I fetch the data from NeDB with async function.
The array was empty because DOM was executed before async function fetching data was executed.
The full code below was fixed one. I'm not sure this is best way, but at least it worked.
let dataM = null;
async function getHTMLData() {
const response = await fetch('/api');
const data = await response.json();
dataM = data;
const base = document.getElementById("base");
for (item of data) {
const root = document.createElement('li');
root.className = "col-md-auto";
root.title = `${item.date}`;
const border = document.createElement('div');
border.className = "row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative";
root.appendChild(border);
const flex = document.createElement('div');
flex.className = "col p-4 d-flex flex-column position-static";
border.appendChild(flex);
const country = document.createElement('strong');
country.className = "d-inline-block mb-2 text-primary";
const title = document.createElement('h3');
title.className = "mb-0";
const date = document.createElement('div');
date.className = "mb-1 text-muted";
date.id = "date";
const fieldItem = document.createElement('p');
fieldItem.className = "mb-auto";
const imageRoot = document.createElement('figure');
imageRoot.className = "image mb-2";
const link = document.createElement('a');
link.className = "p-4";
const linkText = document.createTextNode("Source");
country.textContent = `${item.country}`;
title.textContent = `${item.title}`;
date.textContent = `${item.date}`;
fieldItem.textContent = `${(item.fieldItem)}`;
for (var i = 0; i < item.imageSrc.length; i++) {
const image = document.createElement('img');
image.src = item.imageSrc[i];
image.alt = 'seized items'
image.className = "w-5 h-5";
// image.crossOrigin ="use-credentials";
imageRoot.appendChild(image);
}
const imageText = document.createElement('text');
imageText.innerHTML = `<br>${item.imageText}`;
imageRoot.appendChild(imageText);
link.appendChild(linkText);
link.title = "Source";
link.href = item.URL;
link.className = "";
flex.append(country, title, date, fieldItem, imageRoot, link);
base.appendChild(root);
}
}
sortDate();
async function sortDate() {
const gethtml = await getHTMLData();
const base = await document.getElementById("base");
const myNodeList = await base.getElementsByTagName("li");
const myArray = Array.from(myNodeList);
myArray.sort(function (a, b) {
return new Date(a.title) > new Date(b.title)? -1
: new Date(a.title) < new Date(b.title)? 1
: 0;
})
for (i = 0; i < myArray.length; i++) {
base.appendChild(base.removeChild(myArray[i]))}
}
index.js
app.get('/api', (request, response) => {
database.find({}).exec(function(err, data){
if (err) {
response.end();
return;
}
response.json(data);
})
});

Display CSS GRID with Javascript & DOM

I am trying to create a number of DOM item's using data from my firebase Firestore, however upon running, I have an error in line 34. I am just not quite sure what I should append resultGrid to, to achieve what I am looking for.
<div class="w-layout-grid grid">
<div class="result div-block">
<div class="data-image"></div>
<div class="result-footer">
<div class="results-text">
<h5 class="data-text">Taffy, 8 | Arabian</h5>
<h5 class="data-text">$12,000</h5>
This is my current javascript.
const resultList = document.querySelector('#horseList')
function renderResult(doc){
var resultGrid = document.createElement('div');
resultGrid.className = ('w-layout-grid grid');
var resultDiv = document.createElement('div');
resultDiv.className = ('result');
var resultImage = document.createElement('div');
resultImage.className = ('data-image');
var resultFooter = document.createElement('div');
resultFooter.className = ('result-footer');
var resultText = document.createElement('div');
resultText.className = ('results-text');
var resultButton = document.createElement('button');
resultButton.className = ('button tiny w-button');
resultButton.innerHTML = "View";
//Render text from database inside H5
const string = (`${doc.data().name}, ${doc.data().age} | ${doc.data().type}`);
let resultOne = document.createElement('h5');
let price = document.createElement('h5');
resultOne.className = ('data-text');
price.className = ('data-text');
price.textContent = (`$${doc.data().price}`);
resultOne.textContent = string;
resultList.appendChild(resultGrid);
resultGrid.appendChild(resultDiv);
resultDiv.appendChild(resultImage);
resultDiv.appendChild(resultFooter);
resultFooter.appendChild(resultText);
resultFooter.appendChild(resultButton);
resultText.appendChild(resultOne);
resultText.appendChild(price);
}
//connect to database & get data
const db = firebase.firestore();
db.collection("Horses").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
// doc.data() is never undefined for query doc snapshots
renderResult(doc);
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
Thanks in advance!
I figured it out! I ended up making the div GRID statically in HTML then I just set javascript to create the dynamic div's within that grid!
HTML
<div id="horseList" class="w-layout-grid grid"></div>
Javascript
const resultList = document.querySelector('#horseList')
function renderResult(doc){
var resultDiv = document.createElement('div');
resultDiv.className = ('result');
resultDiv.setAttribute('data-id', doc.id);
var resultImage = document.createElement('div');
resultImage.className = ('data-image');
var resultFooter = document.createElement('div');
resultFooter.className = ('result-footer');
var resultText = document.createElement('div');
resultText.className = ('results-text');
var resultButton = document.createElement('button');
resultButton.className = ('button tiny w-button');
resultButton.innerHTML = "View";
//Render text from database inside H5
const string = (`${doc.data().name}, ${doc.data().age} | ${doc.data().type}`);
let resultOne = document.createElement('h5');
let price = document.createElement('h5');
resultOne.className = ('data-text');
price.className = ('data-text');
price.textContent = (`$${doc.data().price}`);
resultOne.textContent = string;
resultList.appendChild(resultDiv);
resultDiv.appendChild(resultImage);
resultDiv.appendChild(resultFooter);
resultFooter.appendChild(resultText);
resultFooter.appendChild(resultButton);
resultText.appendChild(resultOne);
resultText.appendChild(price);
}

Categories