JavaScript and HTML element manipulation - javascript

Project Concept: Creating an "exam maker", which can be accessed by a teacher to create and let a student be able to access it to take. Many features would be included but to keep it simple on the question at hand i wont be including all info.
Front End: List all questions in the database, using a php file, to a select field in HTML. When the item is selected add it to the test. Display the test, and assign scoring to each question.
My Actual Question/Help: My addq() function is supposed to, get the value of selected item, append it on the global testArray=[]; while the for loop iterates through each one to display them individually after each one is added.
The Problem: What mine is displaying in HTML... it keeps adding the arrays so the output is repeated over and over after each addq(). Please help fix it! -- the array needs to be outside the function so I can access it later and send it off to a php file.
<h4><center>Test</center></h4>
<ol id="test">
</ol>
<script>
var testArray= [];
function addq(){
var addingquestion = document.getElementById('questionSelect').value;
var myArray = testArray.push(addingquestion);
var node = document.createElement("LI");
for(i=0;i<20;i++){
var textnode = document.createTextNode(testArray[i].toString());
node.appendChild(textnode);
document.getElementById("test").appendChild(node);
}
}
</script>
Example Output Issue Picture:
enter image description here

the problem is that you're appending the array every time to the node element. So, every time it will output the old values with the new ones
You don't have to make it as an array because it stacks without an array,
you just need to replace this :
var textnode = document.createTextNode(testArray[i].toString());
with this :
var textnode = document.createTextNode(addingquestion);

Here, you need to be creating you LI each time, it is an object.
var testArray = [1,2,3,4,5,6,7,8,9,10];
function addq() {
// REMOVED because not provided.
//let addingquestion = document.getElementById('questionSelect').value;
//let myArray = testArray.push(addingquestion);
let test = document.querySelector('#test');
testArray.forEach(t => {
// create new li for each item.
let li = document.createElement('li');
let textnode = document.createTextNode(t);
li.appendChild(textnode);
test.appendChild(li);
});
}
addq();
<h4>
<center>Test</center>
</h4>
<ol id="test">
</ol>

Related

How to create multiple todolists using a save button?

Below is a snippet of some of my code. Think a todo list on steriods. I am trying to create multiple Div elements that save to a page that contain a different list every time my "Save button is pressed. whats actually happening is that multiple divs are showing but the original div saved is the only one that gets updated with the list information(so like in a todo list when you click submit a new list item appears ive added a save button and an input field that the user can use to name their list and saves that list to a container but only one div gets updated). I know i'm almost there but ive been looking at this for a couple of hours now and cant quite figure it out. https://github.com/W33K5Y/TODO-PIRPLE
const saveButton = document.getElementById("submit-save");
const myLists = document.getElementById("my-lists");
const startNote = document.getElementById("start-note");
const listName = document.getElementById("new-list-name");
const myUl = document.getElementById("my-ul-lists");
// ! savebutton listener
saveButton.addEventListener("click", addNewTodo);
// ! make new html elements
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
// ! =============== function for creating new todo ================================
function addNewTodo() {
const todoDiv = document.querySelector(".todo-container");
const todos = document.querySelectorAll(".todo-item");
todos.forEach(function(todo) {
createLi(todo);
});
listName.value ? listH1.innerText = listName.value : listH1.innerText = "My List";
newTodoDivWrap.classList.add("new-todo-div");
newTodoDivWrap.appendChild(listH1);
newTodoDivWrap.appendChild(newTodoOl);
myLists.appendChild(newTodoDivWrap);
todoReset(todoDiv, startNote);
startLoginSignUpNoneLobbyFlex();
}
// todo function to go in above that removes all of whats in the tido-container
function todoReset(div, lobbyDiv) {
lobbyDiv.remove();
div.firstElementChild.innerHTML = "";
}
function createLi(todo) {
// ! Create LI
const newTodo = document.createElement('li');
newTodo.innerText = todo.innerText;
newTodo.classList.add("todo-saved-item");
newTodoOl.appendChild(newTodo);
}
I think the following is why it's not working as you intended:
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
Remember that javascript creates references, so when you do something like this—newTodoDivWrap.appendChild(listH1)—you don't add a new element, you only add a reference to said element.
It's the same as if you had two objects.
var a = {'name': 'Anette'}
var bbbb = a // creates a reference, not a new object.
bbbb.name = 'Bjorn'
console.log(a.name) // Bjorn
So create new elements inside the method, instead of creating and calling public ones.
Also, comments like this are so unnecessary:
function createLi(todo) {
// ! Create LI
You had a method name that perfectly explains what it does. You don't need to comment that. Start making it a habit of naming variables or method to explain what's going on—you're already doing that (ex. startLoginSignUpNoneLobbyFlex)—so you don't have to use comments. Comments are useless, unless it's for documentation.
You have to move
const newTodoOl = document.createElement("ol");
const newTodoLi = document.createElement("li");
const listH1 = document.createElement("h4");
into the addNewTodo function. That way each iteration produces a brand new List
Rickard pointed me in the right direction :)

set Interval only seems to happen once when appending a text node to a div [duplicate]

I have a simple forEach loop in which I'm trying to append list items to an unordered list. However, when I run the script, I'm only seeing one list item being added. Can anyone explain why this is happening?
JS
let bookElement = document.getElementsByClassName("book");
let navElement = document.getElementsByTagName("nav")[0];
let unorderedList = document.createElement("UL");
let listItems = document.createElement("LI");
let book1 = new Book();
let book2 = new Book();
let booksArray = [book1, book2];
createNavigation(booksArray, navElement, unorderedList, listItems);
function createNavigation(booksArray, navElement, unorderedList, listItems){
console.log(booksArray)
booksArray.forEach(function(book){
unorderedList.appendChild(listItems);
})
navElement.appendChild(unorderedList);
}
HTML
<body>
<nav></nav>
<div class="book"></div>
</body>
The log in the function is returning that there are two objects in the array.
You only ever create one list item.
You then append it in multiple places.
Since an element can't exist in multiple places at the same time, each time you append it (after the first) you move it.
Use let listItems = document.createElement("LI"); inside your loop.
Yes, there are two objects in the array, but you're adding the same element to the unorganised list twice. So, the second time it's added, the browser sees that the element is already there and doesn't add it again.
A better approach would be to simply create a new li element in each iteration of the loop:
function createNavigation(booksArray, navElement, unorderedList){
console.log(booksArray)
booksArray.forEach(function(book){
let listItems = document.createElement("LI");
unorderedList.appendChild(listItems);
})
navElement.appendChild(unorderedList);
}
Notice that I've removed the listItems parameter as the value passed into it is now unused.
You can take your program a step further, now, by doing something along these lines:
function createNavigation(booksArray, navElement, unorderedList){
console.log(booksArray)
booksArray.forEach(function(book){
let listItems = document.createElement("LI");
listItems.innerHTML = book.title;
unorderedList.appendChild(listItems);
})
navElement.appendChild(unorderedList);
}
That will create a list of book titles, assuming you have titles stored in a title property in your Book constructor.

Custom Javascript not working in Wordpress

My intent is to add an excerpt to each portfolio card within a grid (currently, these only show an image, title and category).
I found a way to insert the excerpt into a card and to iterate through all the cards, but excerpt is not inserting into all of the cards even though the loop is working as expected (logging each iteration). The excerpt will only insert into one card if I specific a specific index of the targetsArray. I left this line commented out for reference.
window.onload = function() {
let targets = document.querySelectorAll('.entry-title');
let newElem = document.createElement('p');
let excerpt = 'This will be the excerpt...';
newElem.innerHTML = excerpt;
let targetsArray = [];
for (let i = 0; i < targets.length; i++) {
targetsArray.push(targets[i]);
}
targetsArray.forEach(target => {
console.log(target);
target.parentNode.insertBefore(newElem, target.nextSibling);
});
// targetsArray[1].parentNode.insertBefore(newElem, targetsArray[1].nextSibling);
};
Note: If you're wondering why I didn't use a simplier method for converting the nodes list into an array, it is because they weren't working.
I tried
const targets = [...document.querySelectorAll(".entry-title")];
and...
Array.from(targets)
For reference this is the page I'm trying to make these changes to
equipourkids.org
I don't know if you are trying to do it with pure JS for a specific reason but Wordpress already loads jQuery by default (if you didn't remove it) and doing that with jQuery should be much more simple then that.
let targets = $('.entry-title');
let newElem = $('<p>This will be the excerpt...</p>')
targets.each(function (idx, item){
$(item).parent().insertBefore(newElem);
});
I just don't understand where exactly you want to insert those exceprt based on your HTML structure. Should that be inside entry-info or what?

How to call/edit all html elements with class names that are found inside an array?

I have managed to create the array with the names that I need. These names are pushed or removed from the array based on user’s clicks on various html elements(buttons).
I am attempting to use the values collected within the array to call changes upon html elements that have class names corresponding/matching the names within the array.
I have managed to create a function that activates a window alert that allows me to see and verify that I am able to cycle through all elements collected within the array. But I got stuck. I couldn’t figure out how to use the individual values/names within the array to call the specific classes of html elements.
I have tried:
for (var a = 0; a < array.length; a++) {
document.getElelemntsByClassName(“.”+array[a]).classList.add(“new”);
//and//
document.querySelectorAll(“.”+array[a]).classList.add(“new”);
//none of them worked. So I wasn’t able to get through to the specific html elements.//
window.alert(“.”+array[a]);
//This responds properly. I can get multiple alerts, one at the time, with all the names I am expecting to see.//
}
Thank you in advance for your help.
I believe you want to use an object instead of an array, since indexes on an array will change as you remove items. That said, you may not even need the object, depending on what you want to do with the element. In the snippet below, I added classNames as an object to treat it as an associative array, for example:
// This is shared between two functions
const LIST_ITEM_SELECTOR = '.js-list-item'
// Get top-level elements
const listElement = document.querySelector('.js-list')
const listItemTemplate = document.querySelector('.js-list-item-template')
const addButton = document.querySelector('.js-add-button')
const logButton = document.querySelector('.js-log-button')
// Replaces "array" from your example
const classNames = {}
// Removes the list item from the list element (also delete from classNames)
const handleDelete = e => {
const parentListItem = e.currentTarget.closest(LIST_ITEM_SELECTOR)
const listItemId = parentListItem.dataset.id
delete classNames[listItemId]
parentListItem.remove()
}
// Updates after each "Add"
let nextId = 0
const handleAdd = () => {
// Build new element from the template
const newListItem = listItemTemplate.content
.cloneNode(true)
.querySelector(LIST_ITEM_SELECTOR)
// Add class to the element and the "classNames" object
const className = `id-${nextId}`
newListItem.classList.add(className)
classNames[nextId] = className
// Add data-id
newListItem.dataset.id = nextId
// Update text
newListItem.querySelector('.js-text').textContent = `Item Text ${nextId}`
// Add delete event listener to the nested x button
newListItem.querySelector('.js-x-button').addEventListener('click', handleDelete)
// Append the newListItem to the end of the list
listElement.appendChild(newListItem)
// Prep the nextId for the next "Add" click
nextId += 1
}
addButton.addEventListener('click', handleAdd)
logButton.addEventListener('click', () => {
console.dir(classNames)
})
<button class="js-add-button">Add</button>
<ul class="js-list"></ul>
<template class="js-list-item-template">
<li class="js-list-item">
<span class="js-text">Item Text</span>
<button class="js-x-button">x</button>
</li>
</template>
<button class="js-log-button">Log Out Data</button>

How to Access an array of objects properties?

i'm working in a simple program that uses an HTML Form to fill an Array with some information, so far, i can get the input data, store it into my list, and visualize it like this :
It basically, converts the Name to a Link, when you click it, it will create a <div> in which i show all the information of the contact.
And i've done this like this :
The error i'm getting is in the last 6 lines of Code.
(I'm trying to avoid all non-troubling code)
var list = [];
var ulList = document.createElement("UL");
function AddToList(){
//Just pushes the info into the list.
}
function Visualize(){
ClearScreen();
for(var i = 0 ; i < list.length ; i++){
//Tried to keep it clean, this just works with each item in the list.
AddToList(i);
}
}
//This Works correctly, it shows every Name i've previously pushed into the list like a Link.
function AddToList(index){
var element = document.createElement("LI");
var name = document.createTextNode(list[index].name);
element.appendChild(name);
var link = document.createElement("A");
link.setAttribute("HREF", "#");
link.appendChild(element);
lik.setAttribute("ID", index);
link.addEventListener("click", ShowInfo(this.id)); //Index would do the same
ulList.appendChild(link);
document.getElementsByTagName("body")[0].appendChild(ulList);
}
//Trouble comes here
function ShowInfo(index){
CleanDIV();
//Previously created <div> with box as id
var box = document.getElementById("box");
var details = document.createElement("UL");
var lName = document.createElement("LI");
var lNumber = document.createElement("LI");
var lMail = document.createElement("LI");
//
//The error is here : Cannot Read Property 'name' of undefined
//And i dont know why, since i've done something similar in a previous line...
//
lName.appendChild(document.createTextNode("Name :" + list[index].name));
lNumber.appendChild(document.createTextNode("Number : " + list[index].number));
lMail.appendChild(document.createTextNode("Mail : " + list[index].mail));
details.appendChild(lName);
details.appendChild(lNumber);
detaisl.appendChild(lMail);
}
I dont even know what kind of mistake i'm making, and was not sure of how to ask this question.
I apologyze for any grammar mistake, my bad variable naming abilities and any lack of quality in my question.
Thank you kindly.
In your AddToList function, indice is 'undefined'
You get the error because you have not added anything to your list array. Add the person details to the list array when the Add to List button is clicked. And retrieve this when the link is clicked.
var name = document.getElementById("txtName").value;
var number = document.getElementById("txtNnumber").value;
...
var person = {'name': name, 'number': number};
list.push(person);
Looks like you have a couple of typos in your code.
lik.setAttribute("ID", indice);
link.addEventListener("click", ShowInfo(this.id)); //Index would do the same
should be
link.setAttribute("ID", index);
link.addEventListener("click", ShowInfo(index)); //Index would do the same

Categories