I'm having some trouble with my code. the only thing i have to make is an add and delete button. The adding part is already done, but the delete part not. it keeps saying:
uncaught TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'
Can someone please help me?
Thanks!
Code:
<input type="text" id="txtelement">
<button id="add">result</button>
<button id="delete">Delete latest</button>
<p id="divResult"></p>
<script>
//decline variable
var index = 1;
//adding option
window.onload = function(){
document.getElementById('add').onclick = function(){
var newElement = document.createElement('div');
varElementid = 'div' + index++;
var node = document.getElementById('txtelement').value;
var newNode = document.createTextNode(node);
newElement.appendChild(newNode);
console.log(newElement);
document.getElementById('divResult').appendChild(newElement);
}
//delete option
document.getElementById('delete').onclick = function(){
var divResult = document.getElementById('divResult');
var alinea = divResult.querySelectorAll('p:last-child')[0];
console.log(alinea + ' word verwijderd...');
divResult.removeChild(alinea);
console.log('verwijderd!');
}
}
:last-child works slightly different than you think it does. p:last-child selects the last child of type p(aragraph) of [whatever parent node you called the method on]'. You don't want to select the p, you want to select the div you just inserted.
var alinea = divResult.querySelectorAll('div:last-child')[0]
Do note that your code doesn't handle the case yet where you delete more elements than you added.
Running code snippet:
//decline variable
var index = 1;
//adding option
window.onload = function() {
document.getElementById('add').onclick = function() {
var newElement = document.createElement('div');
varElementid = 'div' + index++;
var node = document.getElementById('txtelement').value;
var newNode = document.createTextNode(node);
newElement.appendChild(newNode);
console.log(newElement);
document.getElementById('divResult').appendChild(newElement);
}
//delete option
document.getElementById('delete').onclick = function() {
var divResult = document.getElementById('divResult');
var alinea = divResult.querySelectorAll('div:last-child')[0];
console.log(alinea + ' word verwijderd...');
divResult.removeChild(alinea);
console.log('verwijderd!');
}
}
<input type="text" id="txtelement">
<button id="add">result</button>
<button id="delete">Delete latest</button>
<p id="divResult"></p>
Related
<div class="commentArea"></div>
<input class="write" type="text">
<button onclick="summitComment()" class="summit">summit</button>
<script type="text/javascript" src="main.js"></script>
function summitComment() {
let comments = document.getElementsByClassName('commentArea')[0];
let makeDiv = document.createElement('div');
makeDiv.className = 'talking';
comments.appendChild(makeDiv)
let makeUser = document.createElement('span');
let makeMsg = document.createElement('span');
let makeBtn = document.createElement('button');
makeUser.className = "commentUserId";
makeMsg.className = "mentionUserComment";
makeBtn.className = "deleteReply";
makeMsg.innerHTML = reply.value;
makeUser.innerHTML = "User_ID";
makeBtn.innerHTML = "Delete";
for (i=0; 1; i++) {
document.getElementsByClassName('talking')[i].appendChild(makeUser)
document.getElementsByClassName('talking')[i].appendChild(makeMsg)
document.getElementsByClassName('talking')[i].appendChild(makeBtn)
}
}
I'm studying javascript and I try to make comment section for webpage.
first code is HTML code and second is JS code.
but when I write something and click summit button, it's work. but console shows to me error
Uncaught TypeError: Cannot read property 'appendChild' of undefined
I think The tag created by 'createElement' does not seem to be chosen by getElementsByClassName.
I don't know how to solve it.
The reply variable was not defined and this loop on the end I don't think it's needed
function summitComment() {
let comments = document.getElementsByClassName('commentArea')[0];
let reply = document.querySelector('.write');
let makeDiv = document.createElement('div');
makeDiv.className = 'talking';
comments.appendChild(makeDiv);
let makeUser = document.createElement('span');
let makeMsg = document.createElement('span');
let makeBtn = document.createElement('button');
makeUser.className = "commentUserId";
makeMsg.className = "mentionUserComment";
makeBtn.className = "deleteReply";
makeMsg.innerHTML = reply.value;
makeUser.innerHTML = "User_ID";
makeBtn.innerHTML = "Delete";
makeDiv.appendChild(makeUser)
makeDiv.appendChild(makeMsg)
makeDiv.appendChild(makeBtn)
}
<div class="commentArea"></div>
<input class="write" type="text">
<button onclick="summitComment()" class="summit">summit</button>
<script type="text/javascript" src="main.js"></script>
Because appendChild cannot read from undefined
You need check Element exist before append instead of:
var element = document.getElementsByClassName('talking');
for (i=0; 1; i++) {
element?.[i]?.appendChild(makeUser)
element?.[i]?.appendChild(makeMsg)
element?.[i]?.appendChild(makeBtn)
}
Try to use
if (!!comment) comments.appendChild(makeDiv)
instead of only
comments.appendChild(makeDiv)
getElementByClassName returns a single DOM element. You don't need to do '[0]' on it. Remove that and it should work fine.
In case if you use querySelectorAll, then you have get by index since this method returns an array.
I have this part of my html (more than one of same type):
<div class="this-product">
<img src="images/bag2.jpeg" alt="">
<span class="product-name">iPhone</span>
<span class="product-price">345445</span>
</div>
And this part of my javascript code meant to get the innerHTML of the span tags and assign them values as shown:
var productList = document.querySelectorAll('.this-product');
productList.forEach(function (element) {
element.addEventListener('click', function (event) {
var productName = document.getElementsByClassName('product-name')[0].innerHTML;
var productPrice = document.getElementsByClassName('product-price')[0].innerHTML;
var cartProductname = event.currentTarget.productName;
var cartProductprice = event.currentTarget.productPrice;
var cartContent = '<div class="cart-product"><span class="block">'+cartProductname+'</span><span class="block">'+cartProductprice+'</span></div><div class="cart-result">Total = </div><br>'
document.getElementById('dashboard-cart').innerHTML += cartContent;
});
});
Everything works well and every variable above has its value shown well apart from cartProductname and cartProductprice which display as undefined and also vscode tells me that productName is declared but not read. Where could I be wrong?
If I understand your question correctly, you could call querySelector on each product item element that you are iterating like so:
var productList = document.querySelectorAll('.this-product');
productList.forEach(function (element) {
element.addEventListener('click', function (event) {
// Update these two lines like so:
var productName = element.querySelector('.product-name').innerHTML;
var productPrice = element.querySelector('.product-price').innerHTML;
var cartProductname = productName; // event.currentTarget.productName;
var cartProductprice = productPrice; // event.currentTarget.productPrice;
var cartContent = '<div class="cart-product"><span class="block">'+cartProductname+'</span><span class="block">'+cartProductprice+'</span></div><div class="cart-result">Total = </div><br>'
document.getElementById('dashboard-cart').innerHTML += cartContent;
});
});
You can use event.currentTarget.querySelector('.product-name') to get element inside of another element
I have the following code, which creates a custom element, encapsulated with Shadow DOM:
'use strict'
var proto = Object.create(HTMLElement.prototype);
proto.createdCallback = function() {
var root = this.createShadowRoot();
var divEl = document.createElement('div');
divEl.setAttribute("id", "container");
divEl.innerHTML =
"<input id='input' type='text'>"
+ "<br>"
+ "Result: <span id='result'></span>"
+ "<br><button onclick='performTask()'>Run</button>";
root.appendChild(divEl);
};
document.registerElement('custom-ele', {
prototype: proto
});
The idea is, when 'Run' is clicked, the input would be taken from the input element and processed (in performTask()), then the output placed into '#result'. My two questions are:
How would I grab the value from the input field in the Shadow DOM?
How would I place the output into #result?
This
previous stack overflow post looks like it would have answered my question, but all the suggested links are no longer valid so am wondering if anyone could point me in the right direction :)
P.S. I'd rather not use templates since HTML Imports are not being supported by all browsers and I want all of my custom element code contained in one file.
Turns out you can add functions to the shadow root itself, then you can just call this.parentNode.fn() on the shadow roots direct children to access the shadowRoot...
proto.createdCallback = function() {
let root = this.createShadowRoot();
root.innerHTML = "<input id='input' type='text'>"
+ "<br>"
+ "Result: <span id='result'></span>"
+ "<br><button onclick='this.parentNode.process()'>Run</button>";
this.shadowRoot.process = function() {
let spanEle = this.querySelector('span');
let inputEle = this.querySelector('input');
spanEle.textContent = performAlgorithm(inputEle.value.split(','));
};
};
document.registerElement('custom-ele', { prototype: proto });
(Thanks to MarcG for giving me the initial insight)
WITH CLOSURE
You can use the method querySelector on your Shadow DOM root to get inside elements:
'use strict'
var proto = Object.create( HTMLElement.prototype )
proto.createdCallback = function ()
{
//HTML ROOT
var root = this.createShadowRoot()
root.innerHTML = "<input id='input' type='text'>"
+ "<br>"
+ "Result: <span id='result'></span>"
+ "<br><button>Run</button>"
//UI
var buttonEle = root.querySelector( "button" )
var inputEle = root.querySelector( "input" )
var spanEle = root.querySelector( "#result" )
buttonEle.onclick = function ()
{
var input = inputEle.value
// do some processing...
spanEle.textContent = input
}
}
document.registerElement( 'custom-ele', { prototype: proto } )
NB: you can use template without HTML Imports, in the same page. See the following snippet:
<html>
<body>
<custom-ele></custom-ele>
<template id="custelem">
<input id='input' type='text'>
<br>Result:
<span id='result'></span>
<br>
<button>Run</button>
</template>
<script>
var proto = Object.create(HTMLElement.prototype)
proto.createdCallback = function() {
//HTML ROOT
var root = this.createShadowRoot()
root.innerHTML = custelem.innerHTML
//UI
var buttonEle = root.querySelector("button")
var inputEle = root.querySelector("input")
var spanEle = root.querySelector("#result")
buttonEle.onclick = function() {
var input = inputEle.value
// do some processing...
spanEle.textContent = input
}
}
document.registerElement('custom-ele', {
prototype: proto
})
</script>
</body>
</html>
WITHOUT CLOSURE
If you don't want to use closure, you can declare a method called handleEvent on your custom element, and add an Event Listener that will redirect on it:
proto.createdCallback = function ()
{
//HTML ROOT
var root = this.createShadowRoot()
root.innerHTML = custelem.innerHTML
//EVENT
var buttonEle = root.querySelector( "button" )
buttonEle.addEventListener( "click", this )
}
proto.handleEvent = function ( ev )
{
var inputEle = this.shadowRoot.querySelector( "input" )
var spanEle = this.shadowRoot.querySelector( "#result" )
// do some processing...
spanEle.textContent = inputEle.value
}
Here is my code for my current todo list.
<html>
<head>
<title>ToDo</title>
</head>
<body>
<script>
function addText(){
var input = document.getElementById('input').value;
var node = document.createElement("P");
var textnode = document.createTextNode(input);
node.appendChild(textnode);
document.getElementById('do').appendChild(node);
}
</script>
<p id="do"> </p>
<input type='text' id='input'/>
<input type='button' onclick='addText()' value='Add To List'/>
</body>
</html>
It works to add objects but I have no idea what the javascript is to remove objects?
I wonder if someone could help me with a remove script like a X mark on the side of a new added object or something just to remove 1 after you add it,
Cheers
I think I found a solution to your problem. Check my fiddle:
http://jsfiddle.net/Kq4NF/
var c = 1;
function addText(){
var input = document.getElementById('input').value;
var node = document.createElement("P");
node.setAttribute('id', 'anchor'+c);
var textnode = document.createTextNode(input);
node.appendChild(textnode);
var removenode = document.createElement("input");
removenode.setAttribute('type', 'button');
removenode.setAttribute('value', 'X');
removenode.setAttribute("onclick", "removeText('anchor"+c+"')");
node.appendChild(removenode);
c++;
document.getElementById('do').appendChild(node);
}
function removeText(item){
var child=document.getElementById(item);
document.getElementById('do').removeChild(child);
}
Good luck!
var list = document.getElementById("do");
list.removeChild(list.childNodes[0]);
list - represents the p tag with ID do
list.ChildNodes - list of child elements appended to your p tag with ID as do.
list.ChildNodes[0] - represents the first child appended to the list, where 0 is the index.
To remove a specific element, either represent the is as index or point directly the element like
var list = document.getElementById("do");
var node = document.createElement("P");
var textnode = document.createTextNode(input);
textnode.id = "do1"; // Add id to the child element
node.appendChild(textnode);
document.getElementById('do').appendChild(node);
// This is to remove it using ID
list.removeChild(document.getElementById("do1"));
Hope you can understand.
I trying to generate an input (type="button") and setting the onclick-Event to a function, which should hand over a parameter. The whole object should be appended to a div and thats it. Basically this is my try, but I can't see why it does not work.
I pasted the code to jsfiddle, hence its easier for you to reproduce. Click here.
What am I'm doing wrong? I'm learning it by trial and error, so please explain whats wrong. Thanks a lot!
[edit] for the case jsfiddle will be down one day, here is the code I tried to run... :)
<!doctype html>
<html>
<head>
<title>onclick event example</title>
<script type="text/javascript" language="javascript">
var i = 0;
var h = new Array();
function addButton() {
i++;
var container = document.getElementById("check0");
var h[i] = document.createElement("input");
h[i].type = 'button';
h[i].name = 'number' + i;
h[i].value = "number" + i;
h[i].id = 'number' + i;
h[i].onclick = function() {
showAlert(i)
};
container.appendChild(h[i]);
}
function showAlert(number) {
alert("You clicked Button " + number);
}
</script>
</head>
<body>
<div id="check0">
<input type="button" value="klick mich" id="number0" onclick="addButton()"/>
</div>
</body>
</html>
Here is the fixed fiddle for you.
var h[i] = ... is invalid JavaScript.
What you write in the "JavaScript" frame on jsfiddle is executed onload, so this code is not yet present when the HTML you provide is executed (and neither is the addButton() function).
<script>
var i = 0;
var h = new Array();
function addButton() {
i++;
var container = document.getElementById("check0");
h[i] = document.createElement("input");
h[i].type = 'button';
h[i].name = 'number' + i;
h[i].value = "number" + i;
h[i].id = 'number' + i;
h[i].onclick = function() {
showAlert(i)
};
container.appendChild(h[i]);
}
function showAlert(number) {
alert("You clicked Button " + number);
}
</script>
<div id="check0">
<input type="button" value="klick mich" id="number0" onclick="addButton()"/>
</div>
Try using h.push(...) instead of trying to send to a non created element in the array
var x = document.getElementById('pagination');//pagination is an empty div in html
var y ='';
for(var i = 0; i <= (pageMax); i++){
y = y+"<a id ='pageNumber"+i+"' onclick='changePage("+(i+1)+");'>"+(i+1)+"</a>\n ";
} x.innerHTML=y }
i used this to make a pagination for a table. The function will create a row of numbers until button max. 'changePage("+(i+1)+"); ... will call a function and send the i index(number that the page is) of the pagenumber. also i dynamically create a id unique for each number.