How to create a form for comments with the ability of dynamically adding them to the list? - javascript

I need to create a form for comments with the ability to dynamically add them to the list. Each comment should have an assigned ID in consecutive order. The newest comment should be at the very bottom. Comments should be stored in the comments array. Each comment should have properties such as id (number) and text (string). Comments array must be empty when loaded initially. Each click on the "Add" button should create a new object inside the array and create element in the DOM tree.
let nextId = 1;
const comments = [];
const commentForm = document.querySelector('[data-id="comment-form"]');
const commentInput = commentForm.querySelector('[data-input="comment"]');
const button = commentForm.querySelector('[data-action="add"]');
const commentList = commentForm.querySelector('[data-id="comment-list"]');
button.addEventListener('click', () => {
const object = {};
if (commentInput.value != '') {
comments.map(() => ({ id: 'nextId++', text: commentInput.value }));
}
createElement();
});
function createElement() {
const newComment = document.createElement('li');
newComment.setAttribute('data-comment-id', comments.id);
newComment.textContent = comments.text;
commentList.appendChild(newComment);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<link rel="stylesheet" href="./css/styles.css" />
</head>
<body>
<div id="root">
<form data-id="comment-form">
<textarea data-input="comment"></textarea>
<button data-action="add">Add</button>
</form>
<ul data-id="comment-list"></ul>
</div>
<script src="./js/app.js"></script>
</body>
</html>

There are some issues in your code:
You are trying to access commentList from commentForm, but that element is outside of the commentForm. Use document object to access the element.
comments is an array from which you are trying to access text property, there is text property on comments.
You should pass the current input value to the function so that you can set the newly created LI's text with the value.
You should use push() instead of map() to push an item into the array. nextId is a variable but you are using that as if it is a string, you should remove the quotes around it.
For the better user experience, I will suggest you to clear the value of the input after creating the item.
Demo:
let nextId = 1;
const comments = [];
const commentForm = document.querySelector('[data-id="comment-form"]');
const commentInput = commentForm.querySelector('[data-input="comment"]');
const button = commentForm.querySelector('[data-action="add"]');
const commentList = document.querySelector('[data-id="comment-list"]');
button.addEventListener('click', () => {
const object = {};
if (commentInput.value != '') {
comments.push({ id: nextId++, text: commentInput.value });
}
createElement(commentInput.value);
commentInput.value = '';
});
function createElement(ci) {
const newComment = document.createElement('li');
newComment.setAttribute('data-comment-id', comments.id);
newComment.textContent = ci;
commentList.appendChild(newComment);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title></title>
<link rel="stylesheet" href="./css/styles.css" />
</head>
<body>
<div id="root">
<form data-id="comment-form">
<textarea data-input="comment"></textarea>
<button type="button" data-action="add">Add</button>
</form>
<ul data-id="comment-list"></ul>
</div>
<script src="./js/app.js"></script>
</body>
</html>

Related

Why isnt my button displaying value onto the div

I want the button with the id of number1 to display the value of 1 on to the input box which has the id of quest which is short for question.I also want to know if my code can be made more readable.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calucator</title>
<style>
body{
text-align: center;
}
</style>
<script>
const quest = document.getElementById("quest");
const data = quest.value;
const yourElement = document.createElement("div");
function nums(){
const num1 = document.getElementById('number1').innerText = 1;
data.textContent = num1;
}
function run() {
nums()
yourElement.textContent = data
quest.appendChild(yourElement);
}
</script>
</head>
<body>
<h1>Calucator</h1>
<input type="number" placeholder="Enter now" name="" id="quest">
<button onclick="run()">=</button>
<br>
<button onclick="" id="number1">1</button>
</body>
</html>
<script>
const quest = document.getElementById("quest");
const data = quest.value;
const yourElement = document.createElement("div");
//PROBLEM 1: You are not attaching yourElement to the DOM. See Element.insertBefore / Element.appendChild
function nums(){
const num1 = document.getElementById('number1').innerText = 1;
data.textContent = num1;
}
function run() {
nums()
yourElement.textContent = data
quest.appendChild(yourElement);
}
</script>
And
<button onclick="run()">=</button>
Problem 2: Don't use inline element event handling. It isn't safe and Content-Security-Policy won't allow it. Instead, use JavaScript Element.addEventListener(...)

is there a way to assign id or classname to an element through document.createElement?

Im still relatively new to JS. I know i probably shouldnt write my code the way i have done here in the real world, but im only doing this to test my knowledge on for loops and pulling JSON data.
My question is, with the way i have structured my code, is it possible for me to add classnames/Id's to the elements i have made using doc.createElement? for example if i wanted to add custom icons or buttons to each element? I cant seem to think of a way to add them other than having to write out all the HTML and do it that way. Here's my code :
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./styles.css">
<title>Document</title>
</head>
<body>
<section>
</section>
<script src="./app.js"></script>
</body>
</html>
JS
const allCustomers = document.querySelector("section");
let custName = "";
let username = "";
let email = "";
let id = "";
const requestURL = "https://jsonplaceholder.typicode.com/users";
fetch(requestURL)
.then((response) => response.text())
.then((text) => DisplayUserInfo(text));
function DisplayUserInfo(userData) {
const userArray = JSON.parse(userData);
for (i = 0; i < userArray.length; i++) {
let listContainer = document.createElement("div");
let myList = document.createElement("p");
let myListItems = document.createElement("span");
myList.textContent = `Customer : ${userArray[i].name}`;
myListItems.innerHTML =`<br>ID: ${userArray[i].id} <br>Email: ${userArray[i].email} <br>Username: ${userArray[i].username}`;
myListItems.appendChild(myList);
listContainer.appendChild(myListItems);
allCustomers.appendChild(listContainer);
}
}
DisplayUserInfo();
Any pointers would be greatly appreciated as well as any constructive feedback. Thanks
Yes, for sure you can add any attribute for a created element. element.classList.add('class-name-here') for adding class, element.id = 'id-name-here' for adding id.
const allCustomers = document.querySelector("section");
let custName = "";
let username = "";
let email = "";
let id = "";
const requestURL = "https://jsonplaceholder.typicode.com/users";
fetch(requestURL)
.then((response) => response.text())
.then((text) => DisplayUserInfo(text));
function DisplayUserInfo(userData) {
const userArray = JSON.parse(userData);
for (i = 0; i < userArray.length; i++) {
let listContainer = document.createElement("div");
let myList = document.createElement("p");
myList.classList.add('active');
myList.id = 'paragraph'
let myListItems = document.createElement("span");
myList.textContent = `Customer : ${userArray[i].name}`;
myListItems.innerHTML =`<br>ID: ${userArray[i].id} <br>Email: ${userArray[i].email} <br>Username: ${userArray[i].username}`;
myListItems.appendChild(myList);
listContainer.appendChild(myListItems);
allCustomers.appendChild(listContainer);
}
}
DisplayUserInfo();
.active {
color: red;
}
#paragraph {
font-size: 24px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./styles.css">
<title>Document</title>
</head>
<body>
<section>
</section>
<script src="./app.js"></script>
</body>
</html>
is it possible for me to add classnames/Id's to the elements i have
made using doc.createElement
Yes possible with classList for adding class and setAttribute to add id
let listContainer = document.createElement("div");
// To add class
listContainer.className = 'your-class'; //if you have just one
listContainer.classList.add("my-class");//if you want to add multiple
// To add id
listContainer.setAttribute("id", "your_id");
When you use document.createElement it returns an Element. You can use Element attributes and methods to reach what you need. There are some docs for this class on MDN.
This means you can:
> myDiv = document.createElement("div")
<div></div>
> myDiv.id = "test"
'test'
> myDiv
<div id="test"></div>
For classes you can use the attributes className or classList.

How can I make multiple inputs every time I enter an input?

I am creating a google extension called manga extension. It all went well until I crossed with input. I like to put an input number every time I enter a manga name in the main input, naming it with chapter with input. But when I enter a new manga name, the value of every input I entered is lost. And I don't know how to put it inside of localStorage. How should I make it?
const divInput = []
const mangaName = document.getElementById('mangaNameInList')
// the manga name
const deleteBtn = document.getElementById('deleteBtn')
let mangaChapters = document.createElement('input')
let mangaLists = document.getElementById('mangaLists')
// the div i created in html
let count = 0
mangaName.addEventListener('keyup', function (event) {
if (event.key == 'Enter') {
count += 1
mangaLists.innerHTML += `<p> ${mangaName.value}
<em>chapter</em>
<input type="number" class="mangaChapters ${count}"
onkeyup="getValue(event)">
</p>`
// the input that i was conflicted with
}
})
function getValue(event) {
if (event.key == 'Enter') {
mangaChapters = document.getElementsByClassName(`mangaChapters`)
divInput.push(mangaChapters.value)
}
}
every time I entered the main input (mangaName) and displaying it in the innerHTML, I just concatenate it with and and that's the problem, how can I get the value of every declared input that I make in inside the mangaName?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Manga Extension</title>
</head>
<body>
<h1>Manga Name Lists</h1>
<input type="text" id="mangaNameInList">
<button id="deleteBtn">DELETE ALL</button>
<div id="mangaLists"></div>
<script src="script.js"></script>
</body>
</html>
here's the html code. thanks for taking time to answer my coding question :)))

javascript array is being read before creating items

I have created a section including all its content using JS.
const main = document.querySelector('main') ,
new_p = document.createElement('p'),
new_h2 = document.createElement('h2'),
new_div = document.createElement('div'),
new_section = document.createElement('section')
main.appendChild(new_section);
new_section.id = ('section4');
new_section.appendChild(new_div);
new_div.classList.add('landing__container');
new_div.appendChild(new_h2);
new_div.appendChild(new_p);
new_h2.textContent = 'Section 4';
new_h2.id = 'heading4';
new_p.textContent = 'some text goes here'
Then I made an array of all sections (previously created using HTML and newly created using JS).
const sections = Array.from(document.getElementsByTagName("section"))
The problem is that array gets only the sections created with HTML only and can't see the ones created with JS.
here is the array logged to the console (the 3 items in the array are already created with HTML)
(3) [section#section1.your-active-class, section#section2, section#section3]
Anyone can help me how to detect newly created sections with JS?
I tested this code and it's working. JS has no problems here. Maybe you are trying to access sections before the new one is added.
See this snippet:
const main = document.querySelector('main') ,
new_p = document.createElement('p'),
new_h2 = document.createElement('h2'),
new_div = document.createElement('div'),
new_section = document.createElement('section')
main.appendChild(new_section);
new_section.id = ('section4');
new_section.appendChild(new_div);
new_div.classList.add('landing__container');
new_div.appendChild(new_h2);
new_div.appendChild(new_p);
new_h2.textContent = 'Section 4';
new_h2.id = 'heading4';
new_p.textContent = 'some text goes here'
const sections = Array.from(document.getElementsByTagName("section"))
console.log(sections);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- <script type="module" src="./async-await.js"></script> -->
<script type="module" src="./script.js" defer></script>
</head>
<body>
<main>
<section id="section1"></section>
<section id="section2"></section>
<section id="section3"></section>
</main>
</body>
</html>

How to loop pokemons out from the PokeAPI?

Hi I am in the process of fetching data down from the pokeapi, I can loop them out in the console, but when I send them to the div ID__Pokemon only the last index comes out, what is the best way to loop the pokemon names out in ID__Pokemon ?
let myApp = document.querySelector('#App');
const divPokemon = document.getElementById('ID__Pokemon');
const api_url = 'https://pokeapi.co/api/v2/pokemon/';
const pokemonData = async () => {
const response = await fetch(api_url);
const data = await response.json();
for (const item in data.results) {
let pokemon = data.results[item];+
console.log(pokemon.name);
divPokemon.innerHTML = `Pokemon: ${pokemon.name}`;
}
};
pokemonData();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="function.js" defer></script>
</head>
<body>
<div id="App">
<div id="ID__Pokemon"></div>
</div>
</body>
</html>
doing divPokemon.innerHTML = `Pokemon: ${pokemon.name}`; replaces the content with each iteration
Here is an edit of your code which adds a new "li" element to your list, filled with the proper text content
let myApp = document.querySelector('#App');
const divPokemon = document.getElementById('ID__Pokemon');
const api_url = 'https://pokeapi.co/api/v2/pokemon/';
const pokemonData = async () => {
const response = await fetch(api_url);
const data = await response.json();
for (const item in data.results) {
let pokemon = data.results[item];
console.log(pokemon.name);
let newPokemon = document.createElement("li");
newPokemon.innerText = `Pokemon: ${pokemon.name}`;
divPokemon.appendChild(newPokemon);
}
};
pokemonData();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script src="function.js" defer></script>
</head>
<body>
<div id="App">
<div id="ID__Pokemon"></div>
</div>
</body>
</html>

Categories