Adding onclick event on dynamic checkbox - javascript

I'm trying to make a 'CRUD' in pure Javascript, it's almost done, the only thing that I need is preparing the inputs with the value of <li>, to do it, I'd like to add an onclick event in a checkbox that is created dynamically in the function insert(), but everytime I click the checkbox nothing happens.
<!DOCTYPE html>
<html>
<head>
<script>
window.onload = function(){
btnInsert = document.getElementById("btnInsert");
btnEdit = document.getElementById("btnEdit");
btnDelete = document.getElementById("btnDelete");
vname = document.getElementById("tbName");
ul = document.getElementsByTagName("ul")[0];
btnInsert.onclick = insert;
btnDelete.onclick = remove;
}
function insert(){
li = document.createElement("li");
li.innerHTML = vname.value;
li.innerHTML += " <input type='checkbox' onclick='select()' value='Select' /> Update";
ul.appendChild(li);
vname.value = "";
}
function select(){
alert("Checked");
}
function remove(){
var lis = document.getElementsByTagName("li");
for(i = 0; i<lis.length; i++){
lis[i].onclick = function(){
this.remove();
}
}
}
</script>
</head>
<body>
<label for="tbName">Name: </label>
<input name="tbName" id="tbName"/><br /><br />
<button id="btnInsert">Insert</button>
<button id="btnEdit">Edit</button>
<button id="btnDelete">Delete</button>
<br /><br />
<ul>
</ul>
</body>
</html>

It seems the name select is causing conflict since I could get your code working with the following changes:
HTML
li.innerHTML += " <input type='checkbox' onclick='sel()' value='Select' />Update";
Javascript
function sel(){
alert("Checked");
}
Further tests show that if we log the contents of the function with:
li.innerHTML += " <input type='checkbox' onclick='console.log(select.toString)' value='Select' />Update";
the console shows the following
function select() { [native code] }
So my guess is that select is the name of a function already defined by the browser, hence why you can't use it as a name for your functions.
In short, your code triggers another select function, not the one you defined in your source code.

The OP doesn't want it to fire on the LI, he wants it to fire on the checkbox!
Give your dynamic checkbox an ID value like chkBox1.
Now after you have appended it to the document, you can call it with:
var thechkBox=document.getElementById("chkBox1");
Now you can hit thechkBox with:
thechkBox.addEventListener("click", itfired); //itfired is the script that captures the click event.
That is one of many Events you would then have access to (https://www.w3schools.com/js/js_htmldom_events.asp)!
If you needed the dynamic checkbox to perform a function "on"click!

Related

Button that creates a <li> and adds user input on it

The exercise says that my button (like a submit) must use the information set by user in input tag and create an li tag with the text as content. It was my first JavaScript class, so I'm still not familiarised with the syntax.
This is my actual code. I used a querySelector with the id of my existing ul tag, and addEventListener to create an event for the click action. I can't remember how to properly create the new li tag, and don't know how to use the content as info for it.
let myElement = document.querySelector('#add-book');
myElement.addEventListener("click", (e) => {
if (e.target.classList == 'button-add') {
let liElement = document.createElement('li');
let content = document.appendChild(liElement);
content.textContent();
}
});
I hope the button works properly, and show the element in the page by clicking the button (with the typed information).
Oversimplified, but hey, it works:
function AddLi(str)
{
var li = document.createElement('li');
li.appendChild(document.createTextNode(str))
li.innerHTML += ' <button onclick="this.parentNode.remove()">-</button>';
document.getElementById("out").appendChild(li);
}
<form>
<input type="text" name="userinput">
<input type="button" value="Add LI" onclick="AddLi(userinput.value)">
</form>
<span id="out"/>
I guess this is what you want:
(function () {
document.querySelector('#add').addEventListener('click', function () {
let input = document.querySelector('#text');
let list = document.querySelector('#list');
let item = document.createElement('li'); // create li node
let itemText = document.createTextNode(input.value); // create text node
item.appendChild(itemText); // append text node to li node
list.appendChild(item); // append li node to list
input.value = ""; // clear input
});
})();
<div>
<input id="text" type="text" />
<button id="add">Add</button>
</div>
<ul id="list">
<li>example item</li>
</ul>
But please, in the future, ask more specific questions. I don't even know what your problem is, because you don't provide all your code. Also the last sentence of your question is telling me nothing useful at all (.. "I hope the button works properly, and show the element in the page by clicking the button (with the typed information) " ..).
Try
function addBook(book) {
list.innerHTML +=
`<li>${esc(book.value)} <button onclick="del(this)">Del</button></li>`;
book.value = '';
}
function del(item) {
item.parentNode.remove();
}
function esc(s) {
return s.replace(/[&"<>]/g,c =>
({'&':"&",'"':""",'<': "<",'>':">"}[c]));
}
<ul id="list"></ul>
<input id="data" type="text" />
<button onclick="addBook(data)">Add</button>

How would I assign each list item a sequential ID in Javascript? (in an html document by the way)

Here is the section which is confusing me:
<script type="text/javascript">
//declaring veriables
var inputField = document.getElementById("input");
var addBtn = document.getElementById("addBtn");
var html = "";
var x = 0;
addBtn.addEventListener('click', function(){
var text = inputField.value;
addToList(text);
})
//adds items to list
function addToList(text){
html += "<li id=(x+=1)><h4><input type='checkbox' id=(x+=1) onclick= 'clearspecifieditems()'>"+text+"</h4></li>";
document.getElementById("myList").innerHTML = html;
inputField.value = "";
}
//clears items
function clearspecifieditems(itemid)
{
//delete selected item
};
So the goal here is to create a to-do list (I'm new to coding). The addToList(text) function is supposed to create a new list item and assign a sequential ID to it. However, I cannot seem to figure out how to have it generate the ID. In addition, clearspecifieditems(itemid) is supposed to get the IDs of all the list items that are checked, and clear all of them.
For the first part of your question either use string concatenation similar to how you added the text variable...
function addToList(text) {
const id = x + 1;
html += '<li id="' + id + '"><h4><input type="checkbox" id="' + id + '">' + text + '</h4></li>';
// ..
}
...or use a template literal:
function addToList(text) {
const id = x + 1;
html += `<li id="${id}"><h4><input type="checkbox" id="${id}" />${text}</h4></li>`;
// ..
}
HOWEVER, for the second part, how to clear checked boxes:
I purposely left the onclick out of the above code because it sounds as if you need a separate button to clear the checkboxes:
// Grab the button and add an click listener to it
// to call `clearSpecifiedItems`
const button = document.querySelector('.clear');
button.addEventListener('click', clearSpecifiedItems, false);
function clearSpecifiedItems() {
// Select all the checked checkboxes using their class
const selected = document.querySelectorAll('.test:checked');
// Set their checked property to false (or null)
selected.forEach(input => input.checked = false);
}
<input class="test" type="checkbox" />
<input class="test" type="checkbox" />
<input class="test" type="checkbox" />
<input class="test" type="checkbox" />
<button class="clear">Clear</button>
Notice that none of these inputs have IDs. I've used a class to pick up the elements instead. So unless you're using the ids for anything else it makes the first part of your code redundant. Just use a CSS selector to grab the elements you need and then process them. No IDs required!
I can see what you're going for. You are almost there. Just a little bit of syntactical error, and a bit of a logical one.
You see, when you increment x two times, You will have a different id for the <li> and the <input>. What I suggest is you increment the x beforehand and then use it.
You can do it like this:
function addToList(text){
x++;
html += "<li id="+ x +"><h4><input type='checkbox' id="+ x +" onclick= 'clearspecifieditems()'>"+text+"</h4></li>";
document.getElementById("myList").innerHTML = html;
inputField.value = "";
}
or this (ES6)
function addToList(text){
x++;
html += `<li id=${x}><h4><input type='checkbox' id=${x} onclick= 'clearspecifieditems()'>${text}</h4></li>`;
document.getElementById("myList").innerHTML = html;
inputField.value = "";
}
Is it absolutely necessary that you must only increment? Can the ID's be truly unique? I suggest you use UUID in that case
Your second question is how to make clearspecifieditems work. Here's what you can do. You can pass the context, or simply the checkbox that was clicked and then get it's ID easily..
So you would define your function something like this:
function clearspecifieditems(element){
//delete selected item
console.log(element.id); // this would give you the ID of the selected checkbox and then you can do whatever with it
};
and slightly modify your function call on the click event
html += "<li id="+ x +"><h4><input type='checkbox' id="+ x +" onclick= 'clearspecifieditems(this)'>"+text+"</h4></li>";
Note this this part.
More more information, See this
Just use string interpolation to reference the x variable and increment it by one every time you add a new item as follows:
/* JavaScript */
var inputField = document.getElementById("input");
var addBtn = document.getElementById("addBtn");
var output = document.getElementById("output");
var html = "";
var x = 0;
function addToList(text) {
output.innerHTML += `<li id=id${x}><h4><input type='checkbox' id=${x}>This list item has an id: id${x}"</h4></li>`;
inputField.value = "";
x++;
}
addBtn.addEventListener('click', function(){
var text = inputField.value;
addToList(text);
})
<!-- HTML -->
<input type="text" id="input" />
<button id="addBtn">Add Items</button>
<div id="output"></div>
And for removing checked elements, simply add another button, say removeBtn and then add a click listener to the button that invokes the clearspecifieditems().
Inside the function, assign a variable to a list of all the checkboxes, loop through the variable using forEach and remove any checkbox that is not checked like this:
function clearspecifieditems() {
var check = document.querySelectorAll('[id^="id"]');
check.forEach(checkBox => {
if(checkBox.children[0].children[0].checked){
checkBox.remove();
}
});
}
removeBtn.addEventListener('click', clearspecifieditems);
#output {list-style: none;}
/* <input type="text" id="input" />
<button id="addBtn">Add Items</button> */
<ul id="output">
<li id="id0"><h4><input type="checkbox" id="input0">This list item has an id: id0"</h4></li>
<li id="id1"><h4><input type="checkbox" id="input1">This list item has an id: id1"</h4></li>
<li id="id2"><h4><input type="checkbox" id="input2">This list item has an id: id2"</h4></li>
<li id="id3"><h4><input type="checkbox" id="input3">This list item has an id: id3"</h4></li>
</ul>
<hr>
<button id="removeBtn">Remove</button>
You're sending X as 1. You should do like this :
var input = document.getElementById("input");
var div = document.getElementById("div");
var button = document.getElementById("addbutton");
var id = 0;
button.onclick = function() {
text = input.value;
addtask(text)
}
function addtask(text) {
var element = document.createElement("li");
element.setAttribute("id", id)
var deleteE = document.createElement("input");
deleteE.setAttribute("type", "checkbox");
deleteE.setAttribute("onclick", "deleteX(" + id + ")");
var node = document.createTextNode(text);
element.appendChild(deleteE);
element.appendChild(node);
div.appendChild(element);
id += 1;
}
function deleteX(id) {
document.getElementById(id).style.visibility = "hidden";
}
<input id="input"> <button id="addbutton"> add </button>
<div id="div"></br> </div>

Is there a way to dynamically create nested divs onclick?

I'm attempting to create a page where the user is able to customize the form to their needs by adding in extra divs or nested divs (as many layers deep as they'd like). Within each div I'd like to have text input and a button which adds another div on the same level and a button that nests a div within it. Both divs should again have a text input and a button which does the same thing.
However I've gotten a bit stuck. When I attempt to create a nested div I always end up adding it at the very bottom instead of inside its parent.
<html>
<script type="text/javascript">
var counter = 1;
function addNode() {
var newDiv = document.createElement('div');
counter++;
newDiv.innerHTML = "Entry " + counter + " <br><input type='text' name='myInputs'>";
document.getElementById("dynamicInput").appendChild(newDiv);
var newButton = document.createElement('button');
newButton.type = "button";
newButton.onclick = addSub;
document.getElementById("dynamicInput").appendChild(newButton);
}
function addSub() {
var newDiv = document.createElement('div');
counter++;
newDiv.innerHTML = "Entry " + counter + " <br><input type='text' name='myInputs' style='margin:10px'>";
document.getElementById("subInput").appendChild(newDiv);
}
</script>
<form class="form" method="POST">
<div id="dynamicInput" name="dynamicInput" multiple="multiple">
Entry 1<br><input type="text" name="myInputs">
<div id="subInput" name="subInput" multiple="multiple">
<input type="button" value="add nested" onClick="addSub();">
</div>
</div>
<input type="button" value="Add another text input" onClick="addNode();" >
<input type="submit" value = "answer" multiple="multiple"/>
</form>
</html>
Here is a complete solution for you keep in mind that if you need to bind extra events on your produced inputs and buttons you ll have to do it inside the functions addNode or addSub as i did for the click event on the buttons.
Working example : https://jsfiddle.net/r70wqav7/
var counter = 1;
function addNode(element) {
counter++;
var new_entry="Entry "+counter+"<br><input type='text' name='myInputs'><br>";
element.insertAdjacentHTML("beforebegin",new_entry);
}
function addSub(element) {
counter++;
var new_sub_entry="<div class='block'>"
+"Entry "+counter+"<br><input type='text' name='myInputs'><br>"
+"<div class='buttons'>"
+"<input class='add_sub_button' type='button' value='add nested'>"
+"<input class='add_button' type='button' value='Add another text input' >"
+"</div>"
+"</div><br />"
+"</div>";
element.insertAdjacentHTML("beforebegin",new_sub_entry);
var blocks=element.parentNode.getElementsByClassName("block");
blocks[blocks.length-1].getElementsByClassName("add_sub_button")[0].addEventListener("click",function(){
addSub(this.parentNode);
});
blocks[blocks.length-1].getElementsByClassName("add_button")[0].addEventListener("click",function(){
addNode(this.parentNode);
});
}
var buttons=document.getElementsByClassName("add_button");
for(i=0;i<buttons.length;i++){
buttons[i].addEventListener("click",function(){
addNode(this.parentNode);
});
}
var nested_buttons=document.getElementsByClassName("add_sub_button");
for(i=0;i<buttons.length;i++){
nested_buttons[i].addEventListener("click",function(){
addSub(this.parentNode);
});
}
div.block{
padding:5px;
border:2px solid #000;
}
<form class="form" method="POST">
<div class="block">
Entry 1<br><input type="text" name="myInputs"><br>
<div class="buttons">
<input class="add_sub_button" type="button" value="add nested">
<input class="add_button" type="button" value="Add another text input" >
</div>
</div><br />
<input type="submit" value = "answer" multiple="multiple"/>
</form>
EDITED : There was an error binding the click event on nested items updated to work properly
Here's another worked example which makes use of the concepts I mentioned in an earlier comment. I've moved the Add-Item button outside the form and altered the method used to determine the text for each new item added. Rather than keep a counter, I count the number of existing items in the document and increment it, using this as as the n in the string "Entry n"
I should have added(appended) the sub-item before the button that creates new ones, but was lazy and just called appendChild on the button after the other new element was added - the end result is the same, but it's less efficient and will cause slower performance/shorter battery life.
I was going to use the .cloneNode method of the .dynamicInput div, when clicking "Add new item", however this will copy all subitems of the chosen target and we still need to call addEventListener for the button anyway, so I've opted to simply create each input-item added with the "Add new item" button instead.
<!doctype html>
<html>
<head>
<script>
"use strict";
function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);}
function allByClass(className,parent){return (parent == undefined ? document : parent).getElementsByClassName(className);}
function allByTag(tagName,parent){return (parent == undefined ? document : parent).getElementsByTagName(tagName);}
function newEl(tag){return document.createElement(tag);}
function newTxt(txt){return document.createTextNode(txt);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
byId('addNewInputBtn').addEventListener('click', myAddNewItem, false);
var subItemBtn = document.querySelectorAll('.dynamicInput button')[0];
subItemBtn.addEventListener('click', myAddSubItem, false);
}
function makeNewItem(titleStr)
{
var div = newEl('div');
div.className = 'dynamicInput';
var heading = newEl('h3');
heading.innerText = titleStr;
div.appendChild(heading);
var input = newEl('input');
div.appendChild(input);
var btn = newEl('button');
btn.innerText = 'Add sub-items';
btn.addEventListener('click', myAddSubItem, false);
div.appendChild(btn);
return div;
}
function myAddNewItem(evt)
{
var numAlreadyExisting = allByClass('dynamicInput').length; // count number of divs with className = dynamicInput
var newNum = numAlreadyExisting + 1;
var newInputPanel = makeNewItem('Entry ' + newNum);
byId('myForm').appendChild(newInputPanel);
return false;
}
function myAddSubItem(evt)
{
evt.preventDefault(); // stops this button causing the form to be submitted
var clickedBtn = this;
var inputDiv = clickedBtn.parentNode;
var newInput = newEl('input');
inputDiv.appendChild(newInput);
inputDiv.appendChild(clickedBtn);
}
</script>
</head>
<body>
<form id='myForm'>
<div class='dynamicInput'>
<h3>Entry 1</h3>
<input type='text'/><button>Add sub-item</button>
</div>
</form>
<button id='addNewInputBtn'>Add new item</button>
</body>
</html>

creating multiple button using while loop but only first button is responsive when using .onclick function

hi guys i ran in too small issue where i am creating like and dislike function so i created an while loop that created like and dislike for every tag but only the first button are responsive when using .onlick = function
if (mysql_num_rows($res) > 0){
while ($row = mysql_fetch_assoc($res)) {
//blah blah blah
$categories .= "<a href='view_category.php?cid=".$id."' class='cat_links'>".$title." - <font size='-1'>".$description." </a> </font> <div class='rating'><input type='button' id='like1' value='like' /><span id='temp_rating'> ".$rating." </span><input type='hidden' name='cid' id='cid' value='".$id."'/><input type='button' value='dislike' /></div>";
//blah blah blah
}
}
which does this
and the my javascript code is
<script src="ajax.js"></script>
<script>
var submitEvent = document.getElementById("like1").onclick = function(){
likemsg(HTTP);
};
</script>
ajax.js
function likemsg(){
var temp_rating = 1;
var cid = encodeURIComponent(document.getElementById('cid').value);
var url = "category_like_parse.php?temp_rating="+temp_rating+"&cid="+cid;
alert();
HTTP.onreadystatechange=function()
{
if (HTTP.readyState==4 && HTTP.status==200)
{
document.getElementById("temp_rating").innerHTML=HTTP.responseText;
}
}
HTTP.open("POST", url ,true);
HTTP.send();
}
and goes to category_like_parse.php saves +1 to database and echo it and it displays it but only for first like button the rest are unresponsive i got to this conclusion because i used alert(); which only worked for the first one and the rest dint. am i doing anything wrong.
that's because you're creating number of buttons with the same id and that is invalid because id must be unique.
instead assign name to like buttons.
<input type='button' id='like1' name='like' value='like' />
var likeBut= document.getElementsByName("like");
for(var i=0;i<likeBut.length;i++){
likeBut[i].onclick = function(){
likemsg(HTTP);
}
}
In the DOM - IDs of elements are unique identifiers of elements.
When you perform a getElementById it only returns the first element. So you should select them by class or another property instead:
// select all buttons inside something with class=rating
var buttons = document.querySelectorAll(".rating input[type=button]");
// add handlers
for(var i = 0; i < buttons.length; i++){
buttons[i].onclick = function(){
alert("Clicked!");
};
}
Beware of the closure/loop problem and prefer addEventListener to onclick.

delete function is not working to delete div

i have created text filed row in create function . i added delete button in create() function that calls delete when click on button. any help?
<body>
<input type="button" value="createDiv" onclick="create()"/>
</body>
<script type="text/javascript" defer="defer">
function create()
{
var newDiv = document.createElement('div');
newDiv.innerHTML = "<table id='e' border><tr><td><input type='text'><button onclick=del(this.value)</button></td></tr></table>";
// newDiv.className = 'newClass';
document.body.appendChild(newDiv);
}
function del (e) {
if ('function' === typeof e.remove) {
return e.remove();
}
return e.parentNode.removeChild(e);
}
Change:
<button onclick=del(this.value)
to:
<button onclick='del(this)'>
DEMO
Two problems:
You were missing the closing >.
The del function expects to receive the element to delete. The value of the element is not appropriate, especially since the button doesn't have a value.
I'm not sure this will do what you really want. This will just remove the button, it won't remove the table row. If you want to remove the whole table, you need to go up several levels of parentNode until you reach the <table> element.
Also, you should always enclose attribute values in quotes. In this case it works without them, because there are no spaces in the value, but you should get in the habit.
If you want to delete the row then the code should be something like this...
<script type="text/javascript" defer="defer">
function create()
{
var newDiv = document.createElement('div');
var rowId = "someId";
var output = "<table id='e' border><tr id='"+rowId+"'><td ><input type='text'><button onclick=del('"+ rowId +"')>delete</button></td></tr></table>";
newDiv.innerHTML = output;
newDiv.className = 'newClass';
document.body.appendChild(newDiv);
}
function del (id) {
var div = document.getElementById(id);
div.parentNode.removeChild(div);
}
</script>
If so you have done lot of mistake as Barmar Said.
I guess you are missing the quotes and the Button Tag Close tag '>'
<button onclick='del(this.value)'></button>
The HTML code for your button is incorrect. You don't have a closing bracket for the tag, and as there are no delimiters around the onclick attribute value, the closing tag will be part of the value, causing a syntax error in the script.
Try like this:
newDiv.innerHTML = '<table id="e" border><tr><td><input type="text"><button onclick="del(this.value)"></button></td></tr></table>';

Categories

Resources