I'm having trouble making a button that will put text inputted from a box to a list element that is inside an ordered list. My professor asked that I only use createElement, textContent and appendChild (also can't use jQuery), so my options to move the text from the input to li are extremely limited. Here's what I have so far:
let main = function() {
if (this.id == "btn1") {
let listDiv = document.getElementById('div');
let olCreator = document.createElement('OL');
div.appendChild(olCreator).setAttribute("id", "ol");
}
if (this.id == "btn2") {
let olGrab = document.getElementById('OL');
let liCreator = document.createElement('LI');
ol.appendChild(liCreator);
let inputText = document.getElementById("inputBox").textContent;
let liDone = document.getElementById('li').appendChild(inputText);
}
};
I'm pretty sure I don't want to give the li element an id, because if I do, the inputted text will go into every li element, and that'd be bad. As of now, the console tells me this when I press the button in my HTML document:
Uncaught TypeError: Cannot read property 'appendChild' of null
at HTMLButtonElement.main
You are calling appendChild on elements that do not exist or have value null.
Instead of
div.appendChild(olCreator).setAttribute("id", "ol");
try
lastDiv.appendChild(olCreator).setAttribute("id", "ol");
Same in the second condition, change ol.appendChild to olGrab.appendChild
Related
Im making a note taking application and the idea here is im trying to make a selection function to transfer my notes from the side list to the editor on the right side of the screen when clicked. So I have the list items all being created dynamically while the ul is created static.
The trouble im facing is how hard it is to click the list items. I have it console.log the work "click' whenever it registers and im not sure why its not working like its suppose it it looks like it only registers when I click the margins of the children of the li and not the h1 or p tags. Also if I click to the side, it makes my ul clickable which is not good as it would just throw everything in the editor.
I have it so when the li tags are created. It dynamically creates then via JS, adds li,h1,p,p. Appends the h1,p,p tags to the li then the li to the container.
Below is an example of my code:
//This is just to show you what happens when you click
//the submit button and how my divs are being dynamically created.
//I have them being created automatically from
//localstorage on load as well in this same fashion.
submitbutton.addEventListener('click', () => {
//Creating local variables for new notes
let NewNoteContainer = document.createElement('li')
let NewNoteTitle = document.createElement('h1')
let NewNoteDueDate = document.createElement('p')
let NewNoteContent = document.createElement('p')
let RemoveButton = document.createElement('button')
//Adds values of the input boxes to the newley created Elements
NewNoteContainer.id = NoteID
NewNoteContainer.className = 'notes-list-item'
NewNoteTitle.innerHTML = title.value
NewNoteDueDate.innerHTML = dueDate.value
NewNoteContent.innerHTML = content.value
//This appends the newly created elements to the container and then
//Appends the container to its div "note-list-container"
NewNoteContainer.append(NewNoteTitle, NewNoteDueDate,NewNoteContent)
NoteListContainer.append(NewNoteContainer)
//Creates an array, makes it a JSON string. Then stores it in localStorage
let StorageArray = [NoteID,title.value,dueDate.value,content.value]
localStorage.setItem('Note' + NoteID, JSON.stringify(StorageArray))
NoteID += 1
})
//This is the debug function im using to try and diag the click issue.
NoteListContainer.addEventListener('click', (a) => {
if(a.target.parentNode.className == 'notes-list-container') {
console.log('click')
}
})
I have a list with people's data inside it has a li element with 3 p tags inside, one for name, one for address and one for email.
I filled this list manually but due to some changes to my code I had to rewrite this so the html would be made with javascript.
My code looked like this
<p class="adres">#logopedist.Adres</p>
<p class="email">#logopedist.Email</p>
<p class="mobiel">#logopedist.Mobiel</p>
I rewrote this to build the html using javascript. This looks something like this.
var li = document.createElement('li');
li.className = "lijst";
li.id = "lijst";
li.onclick = "ficheVullen(this)";
p.className = "naam";
p.innerHTML = objLogos.Naam[i];
li.appendChild(p);
p.className = "adres";
p.innerHTML = objLogos.Adres[i];
li.appendChild(p);
var p = document.createElement('p');
p.className = "mobiel";
p.innerHTML = objLogos.Mobiel[i];
li.appendChild(p);
My list generates properly. But in my old code I had this at the start of the list.
<li class="lijst" onclick="ficheVullen(this)">
Whenever you would click an li element it would fill a div with the info from the p tags inside that li, so it would fill the div with name, address, mobile,etc
I cannot seem to get this function to work anymore. It only works on the very first LI element and only works for the name. Even though my code is the same and I append classes to the tags like it had in my old code.
The function looks like this:
function ficheVullen() {
FicheNaam = document.getElementById("FicheNaam");
FicheAdres = document.getElementById("FicheAdres");
FicheGSM = document.getElementById("FicheGSM");
FicheNaam.innerHTML = this.querySelector('.naam').textContent;
FicheGSM.innerHTML = this.querySelector('.mobiel').textContent;
FicheAdres.innerHTML = this.querySelector('.adres').textContent;
I get this error now. Cannot read property 'textContent' of null
I call this function here:
window.onload = function() {
changePage(1);
document.getElementById("lijst").addEventListener("click", ficheVullen);
};
The changepage function is part of my pagination where I use javascript to build the list.
When I move the eventlistener out of this I get this error: Cannot read property 'addEventListener' of null.
I hope this gives enough context
You have to use setAttribute to set id.
elm.setAttribute("id", "uniqueId");
Your case : li.setAttribute("id", "lijst")
li.id = "lijst"; will add "id" to object not as attribute
const parent = document.getElementById("container")
let elm = document.createElement("p")
elm.setAttribute("id", "pElm")
elm.innerText = "p tag"
parent.append(elm)
document.getElementById("pElm").style.background = "red"
<div id="container"></div>
I'm trying to loop through an array until it matches the value of the object that is clicked.
When the object is created the text input box shares it's value with the object and the array. I would like to be able to loop through the array until there is a match, then find the index, after that pass the index value to a variable to be used. From there remove the object that is clicked from the webpage and the array.
Additional details are that there is an input box with a button. The user enters a line of information into the input box and selects a button to appendChild it to the list. The object created is a div with the input value as the paragraph with a span element with an X which is supposed to remove the object when clicked.
Here is the HTML Code being used
<div id="outerDiv">
<div id="taskList">
</div>
</div>
Here is the code to create the object.
var magicArray = [];
function makeOutline() {
var textValue = document.getElementById("inputBox").value;
if (textValue == "" || textValue == null){
alert("Please enter a item you want to add to the to-do list");
} else {
var inputField = document.getElementById("taskList");
var inputText = document.createTextNode(textValue);
var mainHeading = document.createElement("p");
mainHeading.setAttribute("class", "outlineBorder");
var spanText = document.createTextNode("x");
var spanBox = document.createElement("span");
spanBox.setAttribute("class", "close");
spanBox.setAttribute("onclick", "removeMe()");
var outlineList = document.createElement("div");
outlineList.setAttribute("value", textValue);
spanBox.appendChild(spanText);
mainHeading.appendChild(inputText);
mainHeading.appendChild(spanBox);
outlineList.appendChild(mainHeading);
inputField.appendChild(outlineList);
magicArray[magicArray.length] = textValue;
document.getElementById("inputBox").value = "";
}
}
Here is the code to remove the item.
I am able to have it set to a static number and work every time; however,
struggling to find a dynamic solution since there can be multiple objects.
function removeMe() {
var removeList = document.getElementById("taskList");
removeList.removeChild(removeList.childNodes[1];
}
Here is a screenshot of the family tree structure
First, you can use this to get the element. docs:
When the event handler is invoked, the this keyword inside the handler is set to the DOM element on which the handler is registered.
function removeMe()
{
// this refers to the item that invoked removeMe()
var removeList = document.getElementById("taskList");
removeList.removeChild(this.parentNode.parentNode);
}
Also, this is how you properly add event listeners
spanBox.addEventListener("click", removeMe);
Here is a working jsfiddle for you
I'm trying to put a delete button on each li using JavaScript and to make an event handler that runs when a button is clicked that removes the li. However when I try to add the handler, I get:
Cannot read property 'addEventListener' of null
I think this is because I am referencing a class that not exist before run the function createbtn. So How can I solve this?
The Code:
I set the variables, put querySelector to buttons because I testing how to do it:
var button = document.getElementById("enter");
var input = document.getElementById("userinput");
var ul = document.querySelector("ul");
var list = document.querySelectorAll ("li");
var buttons = document.querySelector (".btn-danger");
var li = document.createElement("li")
How I create the button:
function createbtn() {
for (var i = 0; i < list.length; i++) {
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Delete"));
btn.classList.add("btn", "btn-danger","btn-sm");
list[i].appendChild(btn);
}
}
The function I try to run:
function liDel(){
li.parentNode.removeChild(li);
}
buttons.addEventListener("click", liDel);
This is my fiddle to see all the code.
The reason why you are getting the null error is because;
You have assigned the variable buttons to a node which doesn't exist yet. (Note that the button is created after the page has been loaded, which means .btn-danger hasn't yet been created at that time).
According to MDN the querySelector method does the the ff:
The Document method querySelector() returns the first Element within the document that matches the specified selector, or group of selectors. If no matches are found, null is returned.
Based on the code you have in the fiddle, here is a guide to achieve the desired results.
First of all, get rid of the global li variable on line 6.
The reason is that if you create a new li from the input, it will render on the same line because it's still referencing the same element node (I'm sure you've realized that)
then in your createListElement function, do the ff
function createListElement() {
var li = document.createElement('li');
li.appendChild(document.createTextNode(input.value));
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Delete"));
btn.classList.add("btn", "btn-danger","btn-sm");
btn.addEventListener('click', function(e){
if(!e) e = window.event;
try{
ul.removeChild(this.parentNode)
}catch(err){
alert(err.message)
}
})
li.appendChild(btn)
ul.appendChild(li);
input.value = "";
}
Then when you create the buttons, you have to attach the event listener function to it. So you do the ff in your createbtn function:
// To create a button
function createbtn() {
for (var i = 0; i < list.length; i++) {
var btn = document.createElement("button");
btn.appendChild(document.createTextNode("Delete"));
btn.classList.add("btn", "btn-danger","btn-sm");
btn.addEventListener('click', function(e){
if(!e) e = window.event;
try{
ul.removeChild(this.parentNode)
}catch(err){
alert(err.message)
}
})
list[i].appendChild(btn);
}
}
anyways, there are more efficient ways to do this. But this is a quick workable model based on the code in your fiddle
Rather than querying and adding the event to the buttons object
try the chaining inside the document load.
window.onload = function () {
document.querySelector('.btn-danger').addEventListener('click', liDel);
};
The above code should work!
Thanks a lot everybody, I got a solution after reading all your answers:
First I got rid the following:
var buttons = document.querySelector (".btn-danger");
var li = document.createElement("li")
Then create this function for remove the "li"
Using "this" you avoid the error for don't have a reference, because with that you don't care in what kind of element this is, you only now something is there and grab it for anything you need.
function liDel(){
ul.removeChild(this.parentNode);
}
and put this in createBtn for delete the existing "li" in the html:
btn.addEventListener('click', liDel);
then put this on createElement for do the same of the above, but for the new "li" creates with the DOM:
btn.addEventListener('click', liDel);
li.appendChild(btn);
And with that the problems was solved.
Thanks again and you can see how the page works on the fiddle
I'm currently learning JavaScript and I'm working on a mock pet adoption site. Super simple layout and functionality except for one issue. I have an error message that comes up when the 'submit' button is pressed and the user tries to submit a pet for adoption without clicking the 'terms and conditions' box. The error comes up, but if I click the button again (without checking the terms and conditions check box), it's like the error just appends another error message.
I am trying to get it where it won't create another error message. I have tried setting the alertMessage variable to an empty string at the end of the function in hopes of it resetting itself, but this does not work.
Thank you in advance for all of your help.
$('#add-pet').on('click', function() {
if (termsBox.checked) {
// Grab info from the form
let $name = $('#pet-name');
let $species = $('#pet-species');
let $notes = $('#pet-notes');
// Assemble the HTML of our new element with the above variables
let $newPet = $(
'<section class="six columns"><div class="card"><p><strong>Name:</strong> ' + $name.val() +
'</p><p><strong>Species:</strong> ' + $species.val() +
'</p><p><strong>Notes:</strong> ' + $notes.val() +
'</p><span class="close">×</span></div></section>'
);
// Attach the element to the page
$('#posted-pets').append($newPet);
// Make the 'x' in the corner remove the section it's contained within
$('.close').on('click', function() {
$(this).parents('section').remove();
});
// Reset form fields
$name.val('');
$species.val('Dog');
$notes.val('');
} else {
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.appendChild(alertMessage);
let termsLabel = document.getElementById('termsLabel');
termsLabel.appendChild(br);
termsLabel.appendChild(span);
alertMessage = '';
}
});
The easiest way is to use innerHTML DOM element property to clean up node's content:
else {
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.appendChild(alertMessage);
let termsLabel = document.getElementById('termsLabel');
termsLabel.innerHTML = ''; // this removes previous content of the node including all it's children
termsLabel.appendChild(br);
termsLabel.appendChild(span);
}
But I would use just:
else {
let termsLabel = document.getElementById('termsLabel');
termsLabel.innerHTML = 'Please read the terms and conditions.';
}
And all styles for termsLabel element should be declared via CSS in a way like
#termsLabel {
margin-top: 15px;
color: red;
}
UPD Here's the fiddler satisfying new requirements: https://jsfiddle.net/yy1z75e7/2/
Clear the element before appending the alert messages
termsLabel.innerHTML = '';
termsLabel.appendChild(br);
termsLabel.appendChild(span);
Or when creating the span give it a class or id, and then check termsLabel to see if it already has the span. If it doesn't then create it, otherwise don't do anything.
//cache this so you don't keep needing to call it over and over
let termsLabel = document.getElementById('termsLabel');
//querySelector() will return null if the span isn't in termsLabel
if(!termsLabel.querySelector('.errorMessage')){
let br = document.createElement('BR');
let alertMessage = document.createTextNode('Please read the terms and conditions.');
let span = document.createElement('SPAN');
span.style.color = '#FF0000';
span.classList.add("errorMessage");
span.appendChild(alertMessage);
termsLabel.appendChild(br);
termsLabel.appendChild(span);
}
This also gives you the ability to remove the message as well
document.querySelector('.errorMessage').remove()
Every time you click the button, and the code in the else clause executes, you are creating new elements. What you want to do instead is to check if the element, termsLabel lets say, is created first, and if it is then change its innerHtml or text values, and if it isn't then create the element instead.