Attaching Event to dynamically created element - javascript

I am working at my 'To Do List'. My goal is to create an 'delete' button inside previously created div, which contains note written by user.
The problem is that I can't use Jquery - click() because it doesn't work with dynamically created elements.
I tried to use on(), but it causes that 'delete' button appears in every note I made.
var ammleng;
var amount = [];
function ammcheck() {
if (amount.length == 0) {
return amount.length;
} else {
return amount.length++;
}
}
function Start() {
var start = document.getElementsByClassName('start')[0];
start.style.display = 'none';
var textarea = document.getElementsByClassName('textarea')[0];
textarea.classList.remove('locked');
var btn = document.getElementsByClassName('btn__container')[0];
btn.classList.remove('locked');
var text = document.getElementsByClassName('text')[0];
text.classList.add('after');
$('.notes').slideDown(2000);
}
function add() {
var txtarea = document.getElementsByClassName('textarea')[0];
ammleng = amount.length;
if (ammleng >= 13) {
alert('Za dużo notatek!')
} else if (txtarea.innerText.length < 1) {
alert('Nic nie napisałeś :(');
} else {
amount[ammcheck()] = document.getElementsByClassName('note');
var text = $('.textarea').html();
var cont = document.getElementsByClassName('notes')[0];
var ad = document.createElement('div');
var adding = cont.appendChild(ad);
adding.classList.add('note');
adding.innerText = text;
txtarea.innerText = '';
}
}
function reset() {
var els = document.getElementsByClassName('notes')[0];
els.innerHTML = '';
amount = [];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='content'>
<div class='logo'>
To Do List
</div>
<div class='text'>
<button class='start' onclick='Start()'>Zaczynajmy</button>
<div class='textarea locked' contenteditable='true' data-text='Wpisz notkę...'></div>
<div class='btn__container locked'>
<button class='dodaj' onclick='add()'>Dodaj</button>
<button class='resetuj' onclick='reset()'>resetuj</button>
</div>
</div>
<div class='notes'></div>
</div>
I tried to make it this way, but it return an error (...'appendChild() is not a function...')
var del = document.createElement('div');
del.classList.add('del');
$('.notes').on('click', '.note', function(){
$(this).appendChild(del);
})

use already existing document to bind click on
$(document).on('click', '.note', function(){
$(this).appendChild(del);
})

Related

HTML Checkbox "onclick" Create Button issue

So i have following objectives from the checkbox click event
1] Create A Button having id = 'id-of-checkbox'+'some-character-here' in specified div
2] Clicking On That Particular Button Will Remove The Button As Well As Checkbox tick related to it
3] If User wants to remove button in specified div through unchecking the checkbox it should be done
4] And If User again checks the checkbox button should be created in specified div
Now i have achieved first 3 objectives and im having issue with 4th one , i.e
if i click on checkbox again after unticking it button is not getting created and console doesnt return any error associated with it.. please help
Here Is My HTML Code
<div id="filterDropArea container">
<input type="checkbox" name="priceFilter" id="priceFilter" class="btn" onclick="updateValue(this.id,this.name)">
Price Filter
</div>
<div id="DropArea">
</div>
Here is My Javascript Code
var objTo = document.getElementById('DropArea');
var checked = ""
function updateValue(id,name)
{
if(document.getElementById(id).checked)
{
checked='yes'
}
else if(!document.getElementById(id).checked)
{
checked='no'
}
if(checked=='yes')
{
addButton(id,name);
}
else if(checked=='no')
{
removeButton(id,name);
}
}
function addButton(id,name)
{
var nameOfButton = name+'X';
var idofButton = id+'11';
var btn = document.createElement("BUTTON");
btn.innerHTML=nameOfButton;
btn.setAttribute("class","btnCancel");
btn.setAttribute("id",idofButton);
btn.setAttribute("onclick","someMsg(this.id)")
objTo.appendChild(btn);
}
function removeButton(id,name)
{
var idofButton = id+'11'
if(document.getElementById('DropArea').contains(document.getElementById(idofButton)))
{
document.getElementById('DropArea').remove(document.getElementById(idofButton));
console.log('Button Removed');
}
}
function someMsg(id)
{
var name = id.substring(0,id.length-2);
document.getElementById(id).remove();
document.getElementById(name).checked=false;
console.log('Deleted');
}
Another approach to achieving the same result:
const dropArea = document.querySelector("#dropArea");
const checkbox = document.querySelector("#priceFilter");
checkbox.addEventListener("change", function(e) {
if (this.checked) {
const btn = createSpecificButton();
dropArea.appendChild(btn);
} else {
const btn = dropArea.querySelector("button");
dropArea.removeChild(btn);
}
});
const createSpecificButton = () => {
const btn = document.createElement("button");
btn.innerText = "Click Here";
btn.addEventListener("click", function(e) {
checkbox.checked = false;
this.remove();
});
return btn;
};
<div id="filterDropArea container">
<input type="checkbox" name="priceFilter" id="priceFilter" /> Price Filter
</div>
<div id="dropArea"></div>
Element.remove() don't have any parameters, so when you call by your way, it will remove DropArea element (includes children, like idofButton).
Solution: Change the below line
document.getElementById('DropArea').remove(document.getElementById(idofButton));
To
document.getElementById(idofButton).remove();
var objTo = document.getElementById('DropArea');
var checked = ""
function updateValue(id, name) {
if (document.getElementById(id).checked) {
checked = 'yes'
} else if (!document.getElementById(id).checked) {
checked = 'no'
}
if (checked == 'yes') {
addButton(id, name);
} else if (checked == 'no') {
removeButton(id, name);
}
}
function addButton(id, name) {
var nameOfButton = name + 'X';
var idofButton = id + '11';
var btn = document.createElement("BUTTON");
btn.innerHTML = nameOfButton;
btn.setAttribute("class", "btnCancel");
btn.setAttribute("id", idofButton);
btn.setAttribute("onclick", "someMsg(this.id)")
objTo.appendChild(btn);
}
function removeButton(id, name) {
var idofButton = id + '11'
if (document.getElementById('DropArea').contains(document.getElementById(idofButton))) {
document.getElementById(idofButton).remove();
console.log('Button Removed');
}
}
function someMsg(id) {
var name = id.substring(0, id.length - 2);
document.getElementById(id).remove();
document.getElementById(name).checked = false;
console.log('Deleted');
}
<div id="filterDropArea container">
<input type="checkbox" name="priceFilter" id="priceFilter" class="btn" onclick="updateValue(this.id,this.name)"> Price Filter
</div>
<div id="DropArea">
</div>

Getting an Uncaught TypeError: Cannot set property 'onclick' of null with <script> at the end

I've looked at previous questions like this and cannot find the answer to my problem. I am working in javascript creating a checkout screen and I have two onclicks for two different html files but when I go to the html file for both it says that the other onclick is null. I have tried window.load and moving the script to the bottom of the
var cart = [];
var search = document.getElementById("addItem");
let placement = 0;
var cartElement = document.getElementById("showCart");
var cartTotal = document.getElementById("totalCart");
search.onclick = function(e) {
var userInput = document.getElementById("query").value;
var cartHTML = "";
e.preventDefault();
placement = 0;
for (i = 0; i < menu.length; i++) {
if (menu[i][0].includes(userInput)) {
cart.push(menu[i]);
placement++;
}
}
if (placement == 0) {
alert("Menu option not included. Please try again.");
}
cart.forEach((item, Order) => {
var cartItem = document.createElement("span");
cartItem.textContent = item[0] + " (" + item[1] + ")";
cartHTML += cartItem.outerHTML;
});
cartElement.innerHTML = cartHTML;
}
window.onload = function() {
var checkout = document.getElementById("addCartButton");
checkout.onclick = function(event) {
cart.forEach()
var cartTotalHTML = "";
event.preventDefault();
cart.forEach(Item, Order => {
var totalInCart = 0;
var writeCart = document.createElement("span");
totalInCart += Order[1];
});
writeCart.textContent = cartTotal += item[1];
cartTotalHTML = writeCart.outerHTML;
cartTotal.innerHTML = cartTotalHTML;
console.log(cartTotal);
}
}
<h3>Search for items in the menu below to add to cart</h3>
<form id="searchMenu">
<input type="search" id="query" name="q" placeholder="Search Menu..."></inpuut>
<input type = "Submit" name= "search" id="addItem" ></input>
</form>
<h4>Your cart: </h4>
<div class="Cart">
<div id="showCart"></div>
</div>
<script src="Script.js"></script>
<h4>Cart</h4>
<button id='addCartButton' class="Cart">Add Cart</button>
<div class="ShowCart">
<div id="totalCart"></div>
</div>
<script src="Script.js"></script>

childNode.remove() doesn't seem to be working

I'm writing a google sheets add on that helps you track data as you play a game. In the sidebar, you can search for a monster in the game and after you hit the submit button the monster's stats, a list of what items they drop after a kill, and a link to the wiki is rendered on screen.
The problem I'm having is that when you search a new monster after having already searched for one, the old items from the drop section won't get removed. The other sections on stats and the wiki link will change, but instead of removing the old drop items, the new items just get added to the end of the list.
I've tried using parent.removeChild() and childNode.remove() and neither seem to do anything and I'm wondering if its because of how google apps script works.
Here is the html for the sidebar itself: note that include() is a custom function that google recommends you add to your script so you can import other files.
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<?!= include('Info sidebar styles'); ?>
</head>
<body>
<form id="monsters">
<input class="monsterInput" type="text"placeholder="Monster Name" name="monsterName" />
<input class="monsterInput" type="text" placeholder="Monster Level" name="monsterLvl" />
<button id="submit">Search</button>
</form>
<div id="output">
</div>
<?!= include('sidebar script'); ?>
</body>
</html>
Here's the code for sidebar script:
<script>
if (document.readyState == 'loading') {
document.addEventListener('DOMContentLoaded', ready)
} else {
ready()
}
function ready(){
// create the divs that are later filled with info
var output = document.getElementById("output");
var stats = document.createElement("div");
stats.id = "statsDiv";
var drops = document.createElement("div");
drops.id = 'dropDiv';
var list = document.createElement("div");
list.id = "dropList";
var wiki = document.createElement("div");
wiki.id = "wiki";
output.appendChild(stats);
output.appendChild(drops);
output.appendChild(wiki);
var index = 0;
// the onSuccess for the onClick eventHandler. data is an object returned from the function call below
function onSuccess(data) {
console.log(`first index ${index}`);
// if the submit button has already been pushed and added the droplist to the DOM, increase the index
if(drops.getElementsByClassName("dropItem")[0]){
index++;
console.log(`second index ${index}`);
};
console.log(index);
// get the stats
var hitpoints = data.hitpoints;
var attackarray = data["attack_type"]
var attackTypes = '';
var attack1 = attackarray[0];
var attack2 = attackarray[1];
var attack3 = attackarray[2];
var attack4 = attackarray[3];
if(attackarray.length === 1){
attackTypes = attack1;
} else if (attackarray.length === 2){
attackTypes = `${attack1}, ${attack2}`;
} else if (attackarray.length === 3){
attackTypes = `${attack1}, ${attack2}, ${attack3}`;
} else if (attackarray.length === 4){
attackTypes = `${attack1}, ${attack2}, ${attack2}, ${attack4}`;
}
var attLvl = data["attack_level"];
var defLvl = data["defence_level"];
var magicLvl = data["magic_level"];
var rangeLvl = data["ranged_level"];
var maxHit = data["max_hit"];
var aggro = '';
if(data.aggressive){
aggro = "Yes";
} else {
aggro = "No";
}
var speed = data["attack_speed"];
// put the stats into html form
var statsInner =
`<h2> Stats </h2>
<ul id="statsList">
<li>Hitpoints: ${hitpoints}</li>
<li>Attack Level: ${attLvl}</li>
<li>Defense Level: ${defLvl}</li>
<li>Magic Level: ${magicLvl}</li>
<li>Ranged Level: ${rangeLvl}</li>
<li>Attack Style: ${attackTypes} </li>
<li>Attack Speed: ${speed}</li>
<li>Max Hit: ${maxHit} </li>
<li>Aggressive? ${aggro} </li>
</ul>`;
stats.innerHTML = statsInner;
drops.innerHTML = '<h2>Drops</h2>';
// Put the wiki url into HTML
var wikiURL = data["wiki_url"];
var wikiInner = `<p>For more info check out this monsters page on the wiki, <a href=${wikiURL}>here</a>.</p>`;
wiki.innerHTML = wikiInner;
// get the drop information and put it in html form. make the data-id attribute of each object equal the value of index
data.drops.forEach(function (item) {
var name = item.name;
var quant = item.quantity;
var members = '';
if(item.members){
members = "(m)";
}
var nameQM = `${name} (x${quant}) ${members}`;
var rarity = (item.rarity) * 100;
var rare = rarity.toFixed(2);
var nameNode = document.createElement("div");
var itemList =
`<p>${nameQM}</p>
<br>
<p> Rarity: ${rare} percent </p>`;
nameNode.innerHTML = itemList;
nameNode.className = "dropItem";
nameNode.dataset.id = index;
list.appendChild(nameNode);
})
drops.appendChild(list);
// if the drop item has a data-id that doesn't match the current index, remove it from the DOM.
var dropArray = list.getElementsByClassName("dropItem");
for(var i = 0; i < dropArray.length; i++){
var item = dropArray[i];
if(item.dataset.id != index){
item.remove();
}
}
}
//add the event listener to the submit button. getMonsterData makes an API call, parses the data, and returns an object filled with the data we add to the DOM through the success handler
document.getElementById("submit").addEventListener("click", function (e) {
e.preventDefault();
var parent = e.target.parentElement;
var monsterName = parent.elements[0].value;
var monsterlvl = parent.elements[1].value;
google.script.run.withSuccessHandler(onSuccess).getMonsterData(monsterName, monsterlvl);
});
}
</script>

Element text not changing when passing selected textContent and new value to an update function

I'm creating a CRUD page where the user can add, delete and edit text, but I have an issue in updating the text after I select it for edit.
In editText function when I click the edit button the text that was added will pop up inside the input field. When I click on the update button (triggering the updateText function), I can see the text in console log but the corresponding html is not updated.
HTML
<div class="main">
<form>
<input type="text" placeholder="search">
</form>
<ul></ul>
<div>
<input class="add-text" type="text" placeholder="Add Text">
<button id="add">Add</button>
<button id="update">update</button>
</div>
</div>
Javascript
const inputsearch = document.querySelector('form input');
const addInputBtn = document.querySelector('#add');
const update = document.querySelector('#update');
addInputBtn.addEventListener('click', addtext);
function addtext(){
let li = document.createElement('li');
let inputadd = document.querySelector('.add-text');
let addedtext = inputadd.value;
let h1Tag = '<h1 id="text">'+addedtext+'</h1>';
let tags = h1Tag + '<button id="delete">Delete</button><button id="edit">Edit</button>';
if(addedtext == ''){
alert('please add some text');
return;
}else{
li.innerHTML = tags;
document.querySelector('ul').appendChild(li);
}
li.querySelectorAll('#delete')[0].addEventListener('click', deleteText);
li.querySelectorAll('#edit')[0].addEventListener('click', editText);
getlist(li, h1Tag);
inputadd.value = '';
}
function deleteText(e) {
e.target.parentNode.remove();
document.querySelector('.add-text').value = '';
}
function editText(e) {
let currentText = e.target.parentNode.firstChild.textContent;
let currentValue = document.querySelector('.add-text');
currentValue.value = currentText;
getupdate(currentText, currentValue);
}
function getupdate(currentText, currentValue) {
update.addEventListener('click', updateText);
function updateText() {
currentText = currentValue.value
console.log(currentText = currentValue.value);
}
}
function getlist(li, h1Tag) {
inputsearch.addEventListener('keyup', serchText);
function serchText(e) {
let typetext = e.target.value.toLowerCase();
if(h1Tag.toLowerCase().indexOf(typetext) != -1){
li.style.display = 'block';
}else{
li.style.display = 'none';
}
}
}
To solve the issue without changing your overall approach, your edit button click needs to get the corresponding element (not just its textContent) and pass it to your getupdate() function to be updated when your update button is clicked. Relatively minor changes to your current functions:
function editText(e) {
const currentText = e.target.parentNode.firstChild;
const currentValue = document.querySelector('.add-text');
currentValue.value = currentText.textContent;
getupdate(currentText, currentValue);
}
function getupdate(currentText, currentValue) {
update.addEventListener('click', updateText);
function updateText() {
currentText.textContent = currentValue.value;
}
}
There are some other issues with your code, particularly the creation of multiple elements with the same id (which is malformed and will likely become problematic as you add additional features). Following is a snippet that addresses that issue as well as simplifying some of your functions and fixing the search.
const search = document.querySelector('form input');
const input = document.querySelector('.add-text');
const container = document.querySelector('ul');
let items = null;
let currentItem = null;
const searchItems = (event) => {
if (items) {
const s = event.currentTarget.value.toLowerCase();
for (const item of items) {
if (item.firstChild.textContent.toLowerCase().indexOf(s) !== -1) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
}
}
};
const deleteItem = (event) => {
currentItem = null;
event.currentTarget.parentNode.remove();
};
const editItem = (event) => {
currentItem = event.currentTarget.parentNode.firstChild;
input.value = currentItem.textContent;
};
const updateItem = () => {
if (currentItem) {
currentItem.textContent = input.value;
}
};
const addItem = () => {
let val = input.value
if (val) {
const li = document.createElement('li');
let inner = '<h1 class="text">' + val + '</h1>';
inner += '<button class="delete">Delete</button>';
inner += '<button class="edit">Edit</button>';
li.innerHTML = inner;
container.appendChild(li);
val = '';
currentItem = li.firstChild;
items = document.querySelectorAll('li');
for (let del of document.querySelectorAll('.delete')) {
del.addEventListener('click', deleteItem);
}
for (let edit of document.querySelectorAll('.edit')) {
edit.addEventListener('click', editItem);
}
} else {
alert('please add some text');
return;
}
};
search.addEventListener('keyup', searchItems);
document.querySelector('#add').addEventListener('click', addItem);
document.querySelector('#update').addEventListener('click', updateItem);
<div class="main">
<form>
<input type="text" placeholder="Search">
</form>
<ul></ul>
<div>
<input class="add-text" type="text" placeholder="Add Text">
<button id="add">Add</button>
<button id="update">Update</button>
</div>
</div>

how do i get same DIV name or id when it change into input field

I want to make editable list like MySQL but i can't get same DIV id when it's change to input field...can anyone tel me how to do that....
this is my code...
//<![CDATA[
$(window).load(function() {
$.fn.editable = function() {
var textBlocks = $(this);
for (var i = 0; i < textBlocks.length; i += 1) {
var textBox = $('<input class="my-text-box" onchange="myFunction(this.value)" />');
var textBlock = textBlocks.eq(i);
textBox.hide().insertAfter(textBlock).val(textBlock.html());
}
textBlocks.dblclick(function() {
toggleVisiblity($(this), true);
});
$('.my-text-box').blur(function() {
toggleVisiblity($(this), false);
});
toggleVisiblity = function(element, editMode) {
var textBlock,
textBox;
if (editMode === true) {
textBlock = element;
textBox = element.next();
textBlock.hide();
textBox.show().focus();
textBox[0].value = textBox[0].value;
} else {
textBlock = element.prev();
textBox = element;
textBlock.show();
textBox.hide();
textBlock.html(textBox.val());
}
};
};
var $edit = $('.makeEditable').editable();
});
function myFunction(val) {
document.writeln(val);
}
<script type='text/javascript' src='//code.jquery.com/jquery-1.9.1.js'></script>
<div class="makeEditable" id="fname">First Name</div>
<div class="makeEditable" id="lname">Last Name</div>
<div class="makeEditable" id="contacts">00 000 0000</div>
<div class="makeEditable" id="email">test#yourdomain.com</div>
please HELP me on this.....
You can get div id when it's change to input field like following.
In if (editMode === true) {} block add var divId = element.attr('id')); like below.
if (editMode === true) {
var divId = element.attr('id'));
console.log(divId);
}
Hope it will help you.

Categories