How to display all the documents from firestore to html - javascript

db.collection('Buses').get().then((snapshot) = > {
snapshot.forEach((busDatas) = > {
busData = busDatas.data()
console.log(busData)
document.getElementById('bus-container-dynamic').innerHTML = `
<div class="single-room-area d-flex align-items-center
mb-50 wow fadeInUp" data-wow-delay="100ms">
<div class="room-thumbnail">
<img src="${busData.ImageLink}" alt="">
</div>
<div class="room-content">
<h2>${busData.TourName}</h2>
<h6>${busData.From} to ${busData.To}</h6>
<h4>₹ ${busData.SeatPrice} </h4>
<div class="room-feature">
<h6>Boarding Point <span>${busData.BoardingTime}</span></h6>
<h6>Dropping Point <span>${busData.DroppingTime}</span></h6>
<h6>Seats Left <span>${busData.SeatsLeft}</span></h6>
<h6>Total Time <span>${busData.TotalTime}</span></h6>
</div>
<a href="#" class="btn view-detail-btn">
View Details
<i class="fa fa-long-arrow-right" aria-hidden="true"></i>
</a>
</div>
</div>`
})})
I am using this code to display my code in html but the only one document is showing on the webpage , but when i print that data in console i am getting all the documents

Do not overwrite the contents of the element on each iteration, append to them.
In fact, use a variable to append to, then assign that to the element, so you only have to manipulate the DOM once.
This line:
document.getElementById('bus-container-dynamic').innerHTML = `...`;
Keeps re-writing the whole contents of #bus-container-dynamic at each iteration.
You could instead store all the data in one variable, then assign that to the element.
A short snippet to illustrate the solution.
const myData = [1,2,3,4,5];
// Create a variable here
let html = '';
myData.forEach( e => {
// Create your element's HTML inside the loop
html += e;
});
// Then assign it to the element
document.getElementById('my-element').innerHTML = html;
<div id="my-element"></div>
And this is how I would modify the code that you posted originally.
db.collection('Buses').get().then((snapshot) = > {
let html = '';
snapshot.forEach((busDatas) = > {
busData = busDatas.data()
console.log(busData)
html += `
<div class="single-room-area d-flex align-items-center
mb-50 wow fadeInUp" data-wow-delay="100ms">
<div class="room-thumbnail">
<img src="${busData.ImageLink}" alt="">
</div>
<div class="room-content">
<h2>${busData.TourName}</h2>
<h6>${busData.From} to ${busData.To}</h6>
<h4>₹ ${busData.SeatPrice} </h4>
<div class="room-feature">
<h6>Boarding Point <span>${busData.BoardingTime}</span></h6>
<h6>Dropping Point <span>${busData.DroppingTime}</span></h6>
<h6>Seats Left <span>${busData.SeatsLeft}</span></h6>
<h6>Total Time <span>${busData.TotalTime}</span></h6>
</div>
<a href="#" class="btn view-detail-btn">
View Details
<i class="fa fa-long-arrow-right" aria-hidden="true"></i>
</a>
</div>
</div>`
document.getElementById('bus-container-dynamic').innerHTML = html;
}) // End foreach
}) // End then

Related

How to look for child elements in a collection

im very new to javascript and probably thats a silly question. What I am trying to achieve is to loop through rows of a "table", get the innerHTML of specific child nodes and multiply them together.
The html looks like this:
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">5</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">2</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
To be specific: I want to get both the values inside the'countChild' and the 'valueChild'. In this example those are 5 and 30 for the first row and for the second row its 2 and 30. Then perform a muiltiplication.
What I tried to do is to get all the parent nodes and then iterating through them to get the child nodes.
const parents = document.getElementsByClassName('parent');
for(var row in parents) {
var count = row.getElementsByClassName('countChild').lastChild.innerHTML;
var value = row.getElementsByClassName('valueChild').lastChild.innerHTML;
....
}
However the debugger already throws an error when im trying to get the childs. The error message is row.getElemenstByClassName is not a function. I guess the collection cannot be used like this and my understanding of how to use js to get information from the document is wrong.
Edit: This is what the tree looks like
<div class="listing-entry">
<div class="value-container d-none d-md-flex justify-content-end">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-end">
<span class="font-weight-bold color-primary small text-right text-nowrap">30</span>
</div>
</div>
</div>
<div class="count-container d-none d-md-flex justify-content-end mr-3">
<span class="item-count small text-right">5</span>
</div>
</div>
You should access parents like an array (not really array but you can cast it to one). Btw, I encourage you to use querySelectorAll and querySelector instead of getElementsByClassName
const parents = document.querySelectorAll(".parent")
parents.forEach(function(row) {
var countChild = row.querySelector(".countChild")
var valueChild = row.querySelector(".valueChild")
var count = countChild ? countChild.innerText : 0
var value = valueChild ? valueChild.innerText : 0
console.log(count, value, count * value)
})
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">5</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">2</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
Edit: I'm using querySelector instead of getElementsByClassName, and checking if child exists before accessing its innerText property.
Edit: here's a function to get all text nodes under a specific node. Then you can combine them and trim the result to get the value you want.
function textNodesUnder(node) {
var all = [];
for (node = node.firstChild; node; node = node.nextSibling) {
if (node.nodeType == 3) {
all.push(node);
} else {
all = all.concat(this.textNodesUnder(node));
}
}
return all;
}
var nodes = textNodesUnder(document.querySelector(".listing-entry"))
var texts = nodes.map(item => item.nodeValue.trim())
console.log(texts)
<div class="listing-entry">
<div class="value-container d-none d-md-flex justify-content-end">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-end">
<span class="font-weight-bold color-primary small text-right text-nowrap">30</span>
</div>
</div>
</div>
<div class="count-container d-none d-md-flex justify-content-end mr-3">
<span class="item-count small text-right">5</span>
</div>
</div>

how can i change <a>exemple</a> to <textarea>exemple</textarea> with onclick function? [duplicate]

This question already has answers here:
Can I change an HTML element's type?
(9 answers)
Closed 4 months ago.
I want help making the java script code to use an icon and when i click the icon the <a>exemple</a> to <textarea>exemple</textarea>
<div class="swiper-slide">
<i class="fa-regular fa-pen-to-square" id="update_pen" onclick="convertElement()"></i> <--- click here
<div class="services-item__content">
<h4 class="services-item__tp-title mb-30">
Exemple <--- change this to textarea with the same text
</h4>
</div>
</div>
This function should replace the <a> with a <textarea>
function update_function(event) {
// from the parent of the event target find the child that is parent to the element you want to replace
let parent = event.target.parentNode.querySelector("div > h4")
// get the target element
let target = parent.querySelector("a")
// store the current value
let text = target.innerText
// remove the old item
parent.removeChild(target)
// create, populate and append the new element to the stored parent
let el = document.createElement("textarea")
el.appendChild(document.createTextNode(text))
parent.appendChild(el)
}
You can hide and show the elements. Something like this
<div class="swiper-slide">
<i class="fa-regular fa-pen-to-square" id="update_pen" onclick="update_function()"></i> <--- click here
<div class="services-item__content">
<h4 class="services-item__tp-title mb-30">
<textarea id="textarea-123" style="display: block;"></textarea>
Exemple <--- change this to textarea with the same text
</h4>
</div>
</div>
<script>
function update_function() {
document.getElementById('anchor-123').style.display = 'none';
document.getElementById('textarea-123').style.display = 'block';
}
</script>
You can try this way to solve this problem
<div class="swiper-slide">
<i class="fa-regular fa-pen-to-square" id="update_pen" onclick="update_function()"></i>
<div class="services-item__content">
<h4 class="services-item__tp-title mb-30" id='demo'>
<a href="" id='myAnchor'>Exemple</a>
</h4>
</div>
</div>
<script>
document.getElementById("myAnchor").addEventListener("click", function(event){
event.preventDefault()
const myElement = document.getElementById("demo");
myElement.innerHTML = "<textarea>exemple</textarea>";
});
</script>

How to insert html element inside the index.html from javascript

I want to insert the card into container using javascript. How do I do it. or make those card display in flex. So it's not like shown in below pic. I have used insertAdjancentHTML to insert the data in note class using javascript. However i'm unable to put them in container.
const addBtn = document.getElementById("add");
const addNewNote = (text = "") => {
const note = document.createElement("div");
note.classList.add("note");
const htmlData = `<div class="card m-4" style="width: 18rem">
<div class="card-body">
<div class="d-flex justify-content-between">
<h5 class="card-title">Card title</h5>
<span class="icons">
<button class="btn btn-primary">
<i class="bi bi-pencil-square"></i>
</button>
<button class="btn btn-primary">
<i class="bi bi-trash"></i>
</button>
</span>
</div>
<hr />
<p class="card-text">
Some quick example text to build on the card title and make up the
bulk of the card's content.
</p>
</div>
</div>`;
note.insertAdjacentHTML("afterbegin", htmlData);
console.log(note);
document.body.appendChild(note);
};
addBtn.addEventListener("click", () => {
addNewNote();
});
Firstly, just use innerHTML - it's an empty element:
note.innerHTML = htmlData;
Secondly, you need to select the element to append this note to. Add an ID:
<div class="container d-flex" id="noteContainer">
And append it like so:
document.getElementById("noteContainer").appendChild(note);
You can add an identifier to the div an use the appendChild to this div instead of the body of the document
<div id="myDiv" class="container d-flex"></div>
And at the end of your function
document.getElementById("myDiv").appendChild(note);
Working example
const button = document.getElementById("addButton")
const addNote = () => {
const myElement = document.createElement('p')
myElement.innerHTML = "Hello world !"
const div = document.getElementById("myDiv")
div.appendChild(myElement)
}
button.addEventListener("click", addNote)
<button id="addButton">Add element</button>
<div id="myDiv"></div>
Cache the container element.
Return the note HTML from the function (no need to specifically create an element - just wrap the note HTML in a .note container), and then add that HTML to the container.
(In this example I've used unicode for the icons, and a randomiser to provide some text to the note.)
const container = document.querySelector('.container');
const addBtn = document.querySelector('.add');
function createNote(text = '') {
return`
<div class="note">
<div class="card m-4" style="width: 18rem">
<div class="card-body">
<div class="d-flex justify-content-between">
<h5 class="card-title">Card title</h5>
<span class="icons">
<button class="btn btn-primary">🖉</button>
<button class="btn btn-primary">🗑</button>
</span>
</div>
<hr />
<p class="card-text">${text}</p>
</div>
</div>
</div>
`;
};
function rndText() {
const text = ['Hallo world', 'Hovercraft full of eels', 'Two enthusiastic thumbs up', 'Don\'t let yourself get attached to anything you are not willing to walk out on in 30 seconds flat if you feel the heat around the corner'];
const rnd = Math.round(Math.random() * ((text.length - 1) - 0) + 0);
return text[rnd];
}
addBtn.addEventListener('click', () => {
const note = createNote(rndText());
container.insertAdjacentHTML('afterbegin', note);
});
<div>
<button type="button" class="add">Add note</button>
<div class="container"></div>
</div>

How to get children of a 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>

loop through divs for nested divs with href inside

<div class="view-content">
<div class="views-row views-row-1">
<div class="views-field">
<span class="field-content">
<a href="link1">Name for link1
<img src="image1">
</a>
</span>
</div>
<div class="views-field-title">
<span class="field-content">
<a href="link1">
</a>
</span>
</div>
</div>
<div class="views-row views-row-2">
<div class="views-field">
<span class="field-content">
<a href="link2">Name for Link2
<img src="image2">
</a>
</span>
</div>
<div class="views-field-title">
<span class="field-content">
<a href="link2">
</a>
</span>
</div>
</div>
I am using node with request, and cheerio to request the data and scrape accordingly.
I am seeking the href from link1 and link2, I got it to work for one link, but it does not scale out when I try to loop it.
const data ={
link:"div.views-field > span > a"
},
pageData = {};
Object.keys(data).forEach(k => {
pageData[k] = $(data[k]).attr("href");});
console.log(pageData);
Your approach with $(data[k]).attr("href"); is the right idea, but there's no loop here. There should be 2 elements matching this selector but your code only grabs the first.
Changing this to a [...$(data[k])].map(e => $(e).attr("href")) lets you get href attributes from all matching elements.
I'm not crazy about pageData being global and using a forEach when a map seems more appropriate, so here's my suggestion:
const $ = cheerio.load(html);
const data = {
link: "div.views-field > span > a",
};
const pageData = Object.fromEntries(
Object.entries(data).map(([k, v]) =>
[k, [...$(v)].map(e => $(e).attr("href"))]
)
);
console.log(pageData);

Categories

Resources