InnerHTML not displaying the content in string - javascript

I am trying to display two buttons with .innerHTML but it doesn't display the content put in the string.
The console is not showing any error and I've checked for typos but I haven't found anything.
Here's my HTML :
<div class="buttons">
<div class="buttons_inner" id="buttonShiny"></div>
</div>
And here's my JS :
const shiny = document.getElementById('buttonShiny');
const displayButtonShiny = (pokemon) => {
const shinyHTMLString = `
<button class="buttons_shiny" onclick="document.getElementById('pokemonSprite').src='https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/${pokemon.id}.png'">Shiny</button>
<button class="buttons_normal" onclick="document.getElementById('pokemonSprite').src='https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png'">Normal</button>
`;
shiny.innerHTML = shinyHTMLString;
};
The content in the shinyHTMLString should be displayed in the #buttonShiny div but it doesn't work
The script tag to call the JS file is right before the closing body tag

Yes you declare the function but never use it. Add only displayButtonShiny("x") to your js code.
const shiny = document.getElementById('buttonShiny');
const displayButtonShiny = (pokemon) => {
const shinyHTMLString = `
<button class="buttons_shiny" onclick="document.getElementById('pokemonSprite').src='https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/${pokemon.id}.png'">Shiny</button>
<button class="buttons_normal" onclick="document.getElementById('pokemonSprite').src='https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${pokemon.id}.png'">Normal</button>
`;
shiny.innerHTML = shinyHTMLString;
};
displayButtonShiny("x"); // x = your pokemon
<div class="buttons">
<div class="buttons_inner" id="buttonShiny">btn1</div>
</div>

Related

Firestore forEach returns one item

I'm creating a project / to-do appliction with firestore.
I want to return all the current projects where the active user has been assigned to.
In a console.log(doc.id, doc.data()), I get the two projects where he has been signed up for.
But when I want to show them both on the home screen, I only see one project.
I don't know what I'm doing wrong
Anyone that can help me?
My function:
const returnProjects = async () => {
const list = document.querySelector<HTMLDivElement>('#projectList');
const projects = query(collectionGroup(db, 'projects'));
const querySnapshot = await getDocs(projects);
querySnapshot.forEach((doc) => {
const deadline = doc.data().Deadline;
const fireBaseTime = new Date(
deadline.seconds * 1000 + deadline.nanoseconds / 1000000,
);
const formatOptions = {
format: 'dd MMM yy',
};
console.log(doc.id, '>', doc.data());
const newElemement = document.createElement('div');
if (list) list.appendChild(newElemement).setAttribute('class', 'projectCard');
const card = document.querySelector<HTMLDivElement>('.projectCard');
if (card) { card.innerHTML = `
<h4>${doc.id, doc.data().Name}</h4>
<p>${fireBaseTime.toLocaleDateString('eng-BE', formatOptions)}</p>
<span>3</span>
`; }
});
};
my Html:
<main>
<div id="dashboard" class="dashboard">
<div class='dashboardUtils'>
<h3 id="dashboardName"></h3>
<span id="currentDate"></span>
</div>
<button id="editDashboard" class="secondary-button"></button>
</div>
<div id='dashboardEdits-form' class="editOpen">
<form id='dashboardEdits' class='edit-form'>
<div id='practicalDisplayname'>
<label for='displayname' class='form-label'>Username</label>
<input type='text' class='form-input' id="displaynameInput" name='displayname'></input>
</div>
</form>
<button id="confirmEdits" class="secondary-button">Save edits</button>
</div>
<div id='amountMessage'>
<h1 id='amountProjects'></h1>
</div>
<div id='projectList'></div>
</main>
A screenshot:
The problem is that for each document in the results you do:
const card = document.querySelector<HTMLDivElement>('.projectCard');
if (card) { card.innerHTML = `
<h4>${doc.id, doc.data().Name}</h4>
<p>${fireBaseTime.toLocaleDateString('eng-BE', formatOptions)}</p>
<span>3</span>
`; }
While you're creating a new project card for each result, the querySelector always returns the first card for the HTML. From the MDN documentation on querySelector:
An Element object representing the first element in the document that matches
So for the second document, you're replacing the innerHTML that you set for the first document.
To solve the problem, since you already have a reference to the element you just generated, add the innerHTML to that instead of looking it up with a query selector:
querySnapshot.forEach((doc) => {
...
const newElement = document.createElement('div');
if (list) list.appendChild(newElemement).setAttribute('class', 'projectCard');
newElement.innerHTML = `
<h4>${doc.id, doc.data().Name}</h4>
<p>${fireBaseTime.toLocaleDateString('eng-BE', formatOptions)}</p>
<span>3</span>
`;
})
The problem you are facing here is caused by the following behavior:
https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild#:~:text=The%20appendChild()%20method%20of%20the%20Node%20interface%20adds%20a%20node%20to%20the%20end%20of%20the%20list%20of%20children%20of%20a%20specified%20parent%20node.%20If%20the%20given%20child%20is%20a%20reference%20to%20an%20existing%20node%20in%20the%20document%2C%20appendChild()%20moves%20it%20from%20its%20current%20position%20to%20the%20new%20position.
What this means is that appendChild will remove the node if already present in the DOM, which is what we are seeing here. This can be easily solved by creating a deep clone of the node first using cloneNode, before appending it to the target div.

i want insert a div block which is created using template letrals inside another template letrals div

I have created multiple template literals <div> blocks like this:
let title = `<div class = prod_detail_${each_response_obj.id} id=${each_response_obj.id}>
<p class = prod_title> Title : ${each_response_obj.title} </p> <br>
</div>`;
I have a parent <div> which is also created using template literals:
let product_div = `<div class=${each_response_obj.handle} id=${each_response_obj.id}_product> </div>
Now I want to insert title inside product_div. I tried, but I couldn't find any solution.
Is that what you mean?
let each_response_obj = {
id:"1",
title:"a",
handle:"c"
}
let title = `<div class = prod_detail_${each_response_obj.id} id=${each_response_obj.id}> <p class = prod_title> Title : ${each_response_obj.title} </p> <br> </div>`
let product_div = `<div class=${each_response_obj.handle} id=${each_response_obj.id}_product> ${title}</div>`
console.log(product_div)
But it works fine

Alternative to document in next.js

I'm still new to learning next.js, but the problem is, I don't understand. How do we call an element from the written html because I want to do like the code written below?
HTML
<div class="container_title">
<div class="main_title">
<h1> Title <span>( Global )</span></h1>
<div class="button_main_title">
<button class="Tap_1 button" >Tap_1 </button>
<button class="Tap_2 button">Tap_2</button>
<button class="Tap_3 button">Tap_3</button>
<button class="Tap_4 button">Tap_4</button>
<button class="Tap_5 button">Tap_5</button>
</div>
</div>
</div>
javascript
const main_title = document.querySelector(".main_title");
const button_main_title = document.querySelectorAll(".main_title button");
(() => {
main_title.addEventListener('click', event => {
if(event.target.classList.contains("button")){
for(i=0;i<button_main_title.length;i++) button_main_title[i].classList.remove("active");
event.target.classList.add("active")
}
})
})();
const Firsr_BTN = document.querySelector(".button_main_title .button:first-child");
Firsr_BTN.click();
NextJS is a framework which is based on React, which is based on Javascript. However, the only way that I know to select an element is to use a React hook called useRef. Let me give you an example.
import React, { useRef } from 'react'
const YourComponent = () => {
const myHeading = useRef()
console.log('heading', myHeading)
return (
<div>
<h1 ref={myHeading}>Heading</h1>
</div>
)
}
Now you have your h1 as myHeading and you can modify it the way you want. Always check your console for what's the element object looks like and how to edit it.

JavaScript stops functioning after adding type=module to src tag in HTML (Using Flask)

What I thought would be the easiest part of my project has turned into a Herculean effort. All I wanted to do was get data from a JSON file to then display on my website. Prior to using a JSON file, I hard coded some data to test my filter/search functionality, all of which I wrote in JavaScript. The code worked perfectly, so I decided to move the data to a JSON file as I am expecting to have a lot more data in the future and can't have it hardcoded. However, I have been unable to get data from the JSON file successfully. I tried using require('./data.json'), but apparently I can't just use require like that. I then tried importing the file, which only works if I go back to the html and add type="module" to the src tag. This then allows all of the data to display on the webpage, however, the function that allows me to filter by category no longer works. When I click on the buttons, I get no response. I used Inspect to get the console to find the error, and the output is:
Uncaught ReferenceError: filterProject is not defined
The search functionality still works, and I suspect this is because that code isn't inside a function. Thus, I don't know why filterProject is supposedly not defined when the other JS code works. Here is all of my code:
import projects from './data.json' assert { type: "json" };
const path = "http://localhost/static/images/";
//ADDING THE HTML, IGNORE
for(let i of projects){
let card = document.createElement("div");
card.classList.add("card", i["category"], "hide");
let imgContainer = document.createElement("div");
imgContainer.classList.add("image-container");
let imageOne = document.createElement("img");
imageOne.setAttribute("src", path.concat(i["imageOne"]));
imgContainer.appendChild(imageOne);
card.appendChild(imgContainer);
let container = document.createElement("div");
container.classList.add("container");
let name = document.createElement("h3");
name.classList.add("project-name");
name.innerText = i["projectName"].toUpperCase();
container.appendChild(name);
let student = document.createElement("h4");
student.classList.add("student-name");
student.innerText = i["studentName"].toUpperCase() + " mentored by " + i["mentor"].toUpperCase();
container.appendChild(student);
let category = document.createElement("h6");
category.innerText = i["category"].toUpperCase().replace("_", " ");
container.appendChild(category);
card.appendChild(container);
document.getElementById("projects").appendChild(card);
}
//FILTERING (DOESNT WORK)
function filterProject(value){
let buttons = document.querySelectorAll(".button-value");
buttons.forEach((button) => {
if(value.toUpperCase() == button.innerText.toUpperCase()){
button.classList.add("active");
}else{
button.classList.remove("active");
}
});
let elements = document.querySelectorAll(".card");
elements.forEach((element) => {
if(value == "all"){
element.classList.remove("hide");
}
else{
//having a space messes it up, make it _
if(element.classList.contains(value.replace(" ", "_"))){
element.classList.remove("hide");
}
else{
element.classList.add("hide");
}
}
});
}
//SEARCH (WORKS)
document.getElementById("search").addEventListener
("click", () => {
let searchInput = document.getElementById("search-input").value;
let elements = document.querySelectorAll(".student-name");
let cards = document.querySelectorAll(".card");
elements.forEach((element, index) =>{
if(element.innerText.includes(searchInput.toUpperCase())){
cards[index].classList.remove("hide");
}
else{
cards[index].classList.add("hide");
}
});
});
//INTIAL STATE
window.onload = () =>{
filterProject("all");
};
Here is the HTML just in case as well:
<div class ="wrapper">
<div id="search-container">
<input type="search" id="search-input" placeholder="Search student name here..."/>
<button id = "search">Search</button>
</div>
<div id ="buttons">
<button class = "button-value" onclick="filterProject('all')">All</button>
<button class = "button-value" onclick="filterProject('Creative Project')">Creative Project</button>
<button class = "button-value" onclick="filterProject('Developing Voice')">Developing Voice</button>
<button class = "button-value" onclick="filterProject('Interdisciplinary Fusion')">Interdisciplinary Fusion</button>
<button class = "button-value" onclick="filterProject('Personal Writing')">Personal Writing</button>
<button class = "button-value" onclick="filterProject('Curriculum Designer')">Curriculum Designer</button>
<button class = "button-value" onclick="filterProject('Internship')">Internship</button>
</div>
<div id = projects></div>
</div>
<script type = "module" src = "{{ url_for('static',filename='javascript/script.js') }}"></script>
If it matters, I am using Flask as my web framework. I'm not sure if that has any impact on anything, but it has created some obstacles when I've tried to create a live server to solve this issue. Thanks in advance for any replies!
What you're looking for is how to load json files locally.
One solution is
Start a local server e.g. http://localhost:8080
Then use fetch() to retrieve the json file
For example, if your data.json file was located within the same folder where you have your html file and where you started your server, then your code could be something like
fetch("http://localhost:8080/data.json")
.then((response) => {
return response.json();
})
.then((data) => {
// Add code to process your data
})

How to append Button inside a container that is being cloned

I have created a <template> tag and i have given it has a few children inside
I'm fetching a json file that has a few objects inside and running a forEach loop after i get the data in order to change the <h1> to be equal and display all the names that are inside the json file. Im also cloning the template and then appending the cloned template to a main tag.
The problem starts when i try to also create a button and append it inside the <div class="content"> that is located inside the template. I tried to get the <div class="content"> inside the loop and later create and append a button to the div i specified above (class = 'content') but whenever i try append it throws this error Uncaught (in promise) TypeError: Cannot read property 'appendChild' of null this is the full code inside the loop.
if I try to change this line contentdiv.appendChild(btn); to this this clone.appendChild(btn); then it works but the button is not inside the <div class="content"> which i want it to be.
Anyone could help me understand what I am doing wrong here ?
const data = [{
fullname: "George Clooney"
}, {
fullname: "Fred Astaire"
}]
data.forEach(actor => {
//clone the template
const clone = template.cloneNode(true);
//get actor name and change the content to be = to the full name inside the json obj
const actorName = clone.querySelector('.actor-name').textContent = actor.fullname;
const contentdiv = document.querySelector('.content');
//create button
const btn = document.createElement('button');
btn.appendChild(document.createTextNode('Read More'));
btn.classList = 'btn'
contentdiv.appendChild(btn);
//apend the the clone to the main tag
main.appendChild(clone);
});
<template id='template'>
<div class="content">
<h1 class="actor-name">
</h1>
</div>
</template>
You need to clone the content
const data = [{
fullname: "George Clooney"
}, {
fullname: "Fred Astaire"
}]
const main = document.getElementById("main");
data.forEach(actor => {
//clone the template
const clone = document.getElementById("template").content.cloneNode(true);
clone.querySelector('.actor-name').textContent = actor.fullname;
const contentdiv = clone.querySelector('.content');
const btn = document.createElement('button');
btn.appendChild(document.createTextNode('Read More'));
btn.classList = 'btn'
contentdiv.appendChild(btn);
main.appendChild(clone);
});
<template id='template'>
<div class="content">
<h1 class="actor-name"></h1>
</div>
</template>
<div id="main"></div>

Categories

Resources