So, recently I made a project where the Javascript just create an element and getting the data from Firebase Firestore database then append it to the body of HTML. This consist of a div which act as the box container with object.className, h4 act as title, some p as texts. But, all of those elements I've added isn't visible on the webpage. But surprisingly, if I open the Inspect element, and call console.log(object) of one of the object, they will show up HTML tag element that exactly what I want and when I hover it, it will show up a highlighted area in the webpage that sized exactly what I want. But, still not visually visible. Actually, in the HTML document, I've added some boxes and element before the element from Javascript, and if I add some new element from the HTML, the element from Javascript is pushed after the newly added element from HTML. So, can someone help me? I'm a newbie in this field. Thank you.
1.) Part of the HTML Element (The Firebase is well set-up here)
<body>
<div class="big-container">
<div class="title">
<span class="title-text">Kompor</span>
</div>
<nav id="wrapper">
<!-- ONE DIV CALLED "IMPORTANT" is necessary for the last box visible -->
<div onclick="" class="box">
<h4 class="title-box">Rinnai 522-E</h4>
<p class="tc-1">HB</p>
<p class="tc-2">313.000</p>
<p class="tc-3">HJ</p>
<p class="tc-4">345.000</p>
</div>
<div onclick="" class="box 2">
<h4 class="title-box">Rinnai 522-A</h4>
<p class="tc-1">HB</p>
<p class="tc-2">313.000</p>
<p class="tc-3">HJ</p>
<p class="tc-4">345.000</p>
</div>
<div onclick="" class="box">
<h4 class="title-box">Rinnai 522-E</h4>
<p class="tc-1">HB</p>
<p class="tc-2">313.000</p>
<p class="tc-3">HJ</p>
<p class="tc-4">345.000</p>
</div>
<div onclick="" class="box">
<h4 class="title-box">Rinnai 522-E</h4>
<p class="tc-1">HB</p>
<p class="tc-2">313.000</p>
<p class="tc-3">HJ</p>
<p class="tc-4">345.000</p>
</div>
<div onclick="" class="box">
<h4 class="title-box">Rinnai 522-E</h4>
<p class="tc-1">HB</p>
<p class="tc-2">313.000</p>
<p class="tc-3">HJ</p>
<p class="tc-4">345.000</p>
</div>
<div onclick="" class="box">
<h4 class="title-box">Rinnai 522-E</h4>
<p class="tc-1">HB</p>
<p class="tc-2">313.000</p>
<p class="tc-3">HJ</p>
<p class="tc-4">345.000</p>
</div>
<div class="box"></div>
<div class="box"></div>
<div class="important"></div>
</nav>
</div>
2.) JS
//DOMstart
const docTarget = document.querySelector('#wrapper');
function insertDoc(doc){
//creation
let box = document.createElement('div');
let header = document.createElement('h4');
let hargaBeli = document.createElement('p');
let p2 = document.createElement('p');
let hargaJual = document.createElement('p');
let p4 = document.createElement('p');
//insertion
header.textContent = doc.data().name;
hargaBeli.innerHTML = "HB";
p2.textContent = doc.data().HB;
hargaJual.innerHTML = "HJ";
p4.textContent = doc.data().HJ;
console.log(box);
console.log(header);
console.log(hargaBeli);
console.log(p2);
console.log(hargaJual);
console.log(p4);
//naming
box.classname = "box";
header.className = "title-box";
hargaBeli.className = "tc-1";
p2.className = "tc-2";
hargaJual.className = "tc-3";
p4.className = "tc-4";
//box-naming plus deletion ops
var hitung = 1;
hitung++;
console.log(hitung);
box.className = "box " + hitung;
box.onclick = function(){
if (confirm('Apa kamu yakin mau menghapus produk ini?')) {
this.parentElement.removeChild(this);
} else {
console.log('Tidak jadi menghapus produk.');
}
}
//appending...
box.appendChild(header);
box.appendChild(hargaJual);
box.appendChild(p2);
box.appendChild(hargaBeli);
box.appendChild(p4);
docTarget.appendChild(box);
console.log(box.className + "Creation Tracker"); //detection
}
//get doc
var doc;
db.collection('Product').get().then((snapshot) => {
snapshot.docs.forEach(doc => {
insertDoc(doc);
})
})
The CSS is connected well and as you can see working well with those elements from HTML document.
As I tried your HTML and javascript code on jsbin, I see that it worked well. The problem is your variable doc, you might add console.log to get the variable again to see why, or you can paste your data structure for further debug.
https://jsbin.com/jeyamoqabu/edit?html,js,output
Related
First of all, i'm a newb to HTML and JS and my english is not the best so sorry about that.
I have an id on a HTML element. I want to add content to this element with a function and create another element (inside the first one), with a new ID and then modify this last ID with a function that runs after the first one.
The id i have defined in HTML is "product-container"
With the function "show product()" i want to create its content and to create a div for its images (id=images-div), which i will add with the function "appendImages()".
I honestly don't know how to do this with only 1 function becouse the item has multiple images and i dont know how to iterate them in a for inside the innerHTML. But i think i should be able to do it this way.
I'm not sure if the problem is that i'm defining the variable (let imagesDiv = document.getElementById("images-div")) before the element is created...
HTML Code:
<div class="list-group" id="product-container"> </div>
JS Code:
const URL = PRODUCT_INFO_URL + localStorage.getItem("productID") + EXT_TYPE
let productContainer = document.getElementById("product-container")
let imagesDiv = document.getElementById("images-div")
let relatedProducts =document.getElementById("related-products")
let currentProduct = [];
function appendImages(){
let HTMLContentToAppend = "";
for (let productImage of product.images){
HTMLContentToAppend +=`
<div class="col-3">
<img src="${productImage}" alt="${product.name}" class="img-thumbnail">
</div>`
}
imagesDiv.innerHTML = HTMLContentToAppend
}
function showProduct(){
let product = currentProduct
productContainer.innerHTML = `
<div class="list-group-item">
<h1> ${product.name} </h1>
<hr>
<div class="col">
<div class="justify-content-between">
<h4 class="mb-1"> Precio </h4>
<p> ${product.currency} ${product.cost}
</div>
<div class="justify-content-between">
<h4 class="mb-1"> Descripción </h4>
<p> ${product.description}
</div>
<div class="justify-content-between">
<h4 class="mb-1"> Categoría </h4>
<p> ${product.category}
</div>
<div class="justify-content-between">
<h4 class="mb-1"> Cantidad de Vendidos </h4>
<p> ${product.soldCount}
</div>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3" id="images-div">
</div>
</div>
</div>`;
appendImages()
};
Thanks in advance for the help and sorry for the newby question :/
What you assumed to be the problem is actually the problem. Move let imagesDiv = document.getElementById("images-div") inside the appendImages function.
I needed three panels to show or hide some of its content based on whether or not a button (p tag) was clicked, and then change the button text when it was clicked to say hide or show depending on the situation. However the hidden content is meant to be auto hidden on mobile devices so I've added some javascript to do this but now the button text change is messed up since its triggering on click. What I would like instead is to have the button text change if the 'clicked-hide' class is added and revert back if it's not. Help would be appreciated :)
HTML
<div class="col-sm compare-card">
<div class="compare-card-header">
<h4 style="display:inline-block">Title</h4>
<img src="images/tooltip.svg">
</div>
<div class="compare-card-balance">
<p class="benefit-title">title</p>
<p class="f-14">subtitle</p>
</div>
<div class="compare-card-attributes">
text here
</div>
<div class="compare-card-footer">
<p class="hide-show-attributes"><span id="toggleShow">Hide Details</span></p>
</div>
</div>
<div class="col-sm compare-card">
<div class="compare-card-header">
<h4 style="display:inline-block">Title</h4>
<img src="images/tooltip.svg">
</div>
<div class="compare-card-balance">
<p class="benefit-title">title</p>
<p class="f-14">subtitle</p>
</div>
<div class="compare-card-attributes">
text here
</div>
<div class="compare-card-footer">
<p class="hide-show-attributes"><span id="toggleShow">Hide Details</span></p>
</div>
</div>
<div class="col-sm compare-card">
<div class="compare-card-header">
<h4 style="display:inline-block">Title</h4>
<img src="images/tooltip.svg">
</div>
<div class="compare-card-balance">
<p class="benefit-title">title</p>
<p class="f-14">subtitle</p>
</div>
<div class="compare-card-attributes">
text here
</div>
<div class="compare-card-footer">
<p class="hide-show-attributes"><span id="toggleShow">Hide Details</span></p>
</div>
</div>
Javascript
//COMPARISON CARD SCRIPT---------------
//This wll show and hide the card attributes section inside the card
jQuery('.hide-show-attributes').on('click', function() {
jQuery('.compare-card-attributes').toggleClass('clicked-hide');
});
//This will toggle the text on the show hide p tag button messaging
jQuery(document).ready(function($) {
$('.compare-card-footer').find(".hide-show-attributes").click(function(){;
if($(this).find("span.toggleShow").first().text()=="Hide Details"){
$("span.toggleShow").text("Show Details");
}
else {
$("span.toggleShow").text("Hide Details");
}
});
});
//Mobile Switch - this will auto collapse the panel when the user is on mobile
if($(window).width()<600){
$(".compare-card-attributes").addClass("clicked-hide");
$('span.toggleShow').text('Show Details');
}
else {
$(".compare-card-attributes").removeClass("clicked-hide");
}
// this is used whenever the window is resized
$(window).resize(function(){
if($(window).width()<600){
$(".compare-card-attributes").addClass("clicked-hide");
}
else {
$(".compare-card-attributes").removeClass("clicked-hide");
}
});
//END COMPARISON CARD SCRIPT---------------
First of all i suggest you set .compare-card-attributes to hidden on mobile with CSS
#media only screen and (max-width: 600px) {
.compare-card-attributes {
visibility: hidden;
}
}
and also have a class of something along the lines of
.hidden {
visibility: hidden;
}
then your script will need to be (assuming these jquery methods are already working)
jQuery('.hide-show-attributes').on('click', function() {
const cardAttributes = $('.compare-card-attributes');
const toggleText = $(this).find("span.toggleShow").first();
cardAttributes.toggleClass('hidden');
if(cardAttributes.hasClass("hidden")){
toggleText.text("Show Details");
}
else {
toggleText.text("Hide Details");
}
});
I have written that blindly, so i hope that works / helps.
I suggest you use a more semantic element for your toggle too, like a button or div with a 'role=button' attribute.
I have some HTML / JS code looking like this.
var bTags = document.getElementsByClassName("Wrapper");
var kind = bTags[0];
console.log(kind);
console.log(kind.childNodes[4].text);
<div class="Wrapper">
<h3 class="date" id="date">{{date}}</h3>
<div class="descriptionWrapper">
<p class="jobDescription">{{job}}</p>
<p class="jobAreaDescription">{{jobArea}}</p>
<p class="placeDescription">{{ort}}</p>
<p class="kindDescription">{{anstellung}}</p>
</div>
<div class="jobLink">
{{#custom_link jobLink}}
{{linkText}}
{{/custom_link}}
</div>
</div>
In my example the "console.log(kind);" successfully logs the HTML object. Here its not working of course because its not defined.
But somehow the childNodes[0-4].text is undefined. I just want to access the text of the p element with the class "placeDescription" of this specific parentNode.
const el = document.querySelector('.Wrapper p:nth-of-type(3)');
if (el) {
console.log(el.textContent)
}
Having a code like this:
<div id="myid">
<div class="test">
<h3 class="h3_class">My Title</h3>
<p class="class_1_p">Text 1</p>
<p class="Sans-19px">
test text 3
</p>
</div>
</a>
</div>
<div class="test_light">
<blockquote class="test_text_final">
An example final text
</blockquote>
</div>
</div>
It is possible to take the inner HTML using the following code:
document.querySelector('div#myid').innerText
Is there any way to separate which let's say a comma the text from every tag?
Expected output:
My Title,Text 1,test text 3,An example final text
Not directly with innerText. What you would have to do is iterate through the HTML recursively until you got to the last leaf that only has text, and then return each of those.
const root = document.querySelector('#myid');
const getTexts = (el, chunks = []) => {
if (el.nodeType === document.TEXT_NODE) {
return chunks.concat(el.data);
} else if (el.childNodes.length > 0) {
return Array.prototype.reduce.call(el.childNodes, (result, child) => getTexts(child, result), chunks);
}
return chunks;
}
console.log(getTexts(root));
<div id="root">
<div id="myid">
<div class="test">
<h3 class="h3_class">My Title</h3>
<p class="class_1_p">Text 1</p>
<p class="Sans-19px">
test text 3
</p>
</div>
</div>
<div class="test_light">
<blockquote class="test_text_final">
An example final text
</blockquote>
</div>
</div>
As you'll notice, this function also includes newlines (\n) and spaces, which you can filter out if you want.
The function basically goes through each node. If it is a TextNode, it reads the text and adds it to the chunk. If it's not, but has children, it'll then recurse through each of the children. If it's neither, it just returns the existing chunks.
const root = document.querySelector('#root');
const getTexts = (el, chunks = []) => {
if (el.nodeType === document.TEXT_NODE) {
return chunks.concat(el.data);
} else if (el.childNodes.length > 0) {
return Array.prototype.reduce.call(el.childNodes, (result, child) => getTexts(child, result), chunks);
}
return chunks;
}
console.log(
getTexts(root).map(s => s.trim()).filter(Boolean)
);
<div id="root">
<div id="myid">
<div class="test">
<h3 class="h3_class">My Title</h3>
<p class="class_1_p">Text 1</p>
<p class="Sans-19px">
test text 3
</p>
</div>
</div>
<div class="test_light">
<blockquote class="test_text_final">
An example final text
</blockquote>
</div>
</div>
This loops through all elements in #myid and if the text input is more than 0, it adds to result and then gives you an alert, is this what you want?
var result = "";
$("#myid *").each(function(index) {
if($(this).text().length > 0) {
result += $(this).text().replace(/(\r\n|\n|\r)/gm,"") + ",";
}
});
alert(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myid">
<div class="test">
<h3 class="h3_class">My Title</h3>
<p class="class_1_p">Text 1</p>
<p class="Sans-19px">
test text 3
</p>
</div>
</a>
</div>
<div class="test_light">
<blockquote class="test_text_final">
An example final text
</blockquote>
</div>
</div>
Edit: Consider using Boris's solution instead.
Here's a VanillaJS one line solution:
var text = document.querySelector('div#myid').innerText;
console.log(text.split('\n').filter(x => x).join(', '));
<div id="myid">
<div class="test">
<h3 class="h3_class">My Title</h3>
<p class="class_1_p">Text 1</p>
<p class="Sans-19px">
test text 3
</p>
</div>
<div class="test_light">
<blockquote class="test_text_final">
An example final text
</blockquote>
</div>
</div>
This one grabs everything inside given selector.
console.log(document.getElementById("myid").innerText.replace(/\s{2,}/g,', '));
<div id="myid">
<div class="test">
<h3 class="h3_class">My Title</h3>
<p class="class_1_p">Text 1</p>
<p class="Sans-19px">
test text 3
</p>
</div>
</a>
</div>
<div class="test_light">
<blockquote class="test_text_final">
An example final text
</blockquote>
</div>
</div>
I'm completely new to JavaScript and struggling to get this working. I'm trying to display contact details in an alert box when a button is clicked.
The information is displayed in nested DIVs outlined below:
<div class="info-and-actions">
<div class="info">
<div class="name-container">
<h4 class="name">Trader 1</h4>
</div>
<div class="details-container">
<p class="tele">###############</p>
<p class="email">hello#url.com</p>
</div>
<div class="actions">
<button class="displayContactDetails">Display contact details</button>
</div>
</div>
</div>
<div class="info-and-actions">
<div class="info">
<div class="name-container">
<h4 class="name">Trader 2</h4>
</div>
<div class="details-container">
<p class="tele">###############</p>
<p class="email">hello#url.com</p>
</div>
<div class="actions">
<button class="displayContactDetails">Display contact details</button>
</div>
I am using this JavaScript with an event listener on the displayContactDetails button to display the contact details in the alert box.
function displayContactDetails() {
var contactName = document.querySelector("a.name-link.profile-link").textContent;
var contactTele = document.querySelector("p.tele").textContent;
alert("Contact " + contactName + " on " + contactTele);
}
This currently displays the first trader's contact details when any displayContactDetails button is clicked.
What I want to do is select the relevant contact information from the parent elements of the button (.name-container and .details-container) - so when the second button is clicked, Trader 2's details are displayed.
How do I traverse the DOM to achieve this?
Your event will have the necessary info to locate the corresponding telephone element.
function displayContactDetails(e) {
var contactName = e. currentTarget // this is the element that has the click listener
.parentNode // this would be .actions div
.parentNode // this would be .info div
.querySelector('.name a') // the link with the name
.innerHTML; // the inner contents of the link, in this case the name
// repeat but change querySelector to grab the telephone
alert("Contact " + contactName + " on " + contactTele);
}
or easier with jquery
$('.displayContactDetails').on('click', function(e){
var name = $(this)
.closest('.info') // goes up in the tree until .info
.find('.name').html(); // then back to .name and get content
alert(name);
});
With jquery it is not only easier, but it is also more resilient to changes in the html structure. Jquery will go up the DOM tree until it finds the .info div. With plain js you have to hardcode the number of times to jump to the parent element, or make a loop for it.
You can also try the other answers suggested but you also have to maintain the additional id's and markup required for it to work.
i hope passing a unique info on the function call
function displayContactDetails(id){
var contactName = document.getElementById("name-link-"+id).textContent;
alert("Contact " + contactName );
}
<div class="info-and-actions">
<div class="info">
<div class="name-container">
<h4 class="name">Trader 1</h4>
</div>
<div class="details-container">
<p class="tele">###############</p>
<p class="email">hello#url.com</p>
</div>
<div class="actions">
<button class="displayContactDetails" onclick="displayContactDetails('one')">Display contact details</button>
</div>
</div>
</div>
<div class="info-and-actions">
<div class="info">
<div class="name-container">
<h4 class="name">Trader 2</h4>
</div>
<div class="details-container">
<p class="tele">###############</p>
<p class="email">hello#url.com</p>
</div>
<div class="actions">
<button class="displayContactDetails" onclick="displayContactDetails('two')">Display contact details</button>
</div>