Im trying to add button "edit" and "delete" into list element after clicking on it.
Ive added 2 buttons to list element and set their display to none in class btnedit and btndelete:
function Add(){
let li = document.createElement('li');
let a = document.createElement('a');
let button1 = document.createElement('button');
let button2 = document.createElement('button');
button1.innerHTML = "Edit";
button2.innerHTML = "Delete";
button1.setAttribute('class','BtnEdit');
button2.setAttribute('class','BtnDelete');
let input = document.getElementById('AddText').value;
if (input.length < 3){
alert('Must be longer than 3');
}
else if(input.length > 255){
alert('Cant be longer than 255');
}
else {
if (checkDate()!=null) {
let date = checkDate();
let t = document.createTextNode(`${input} ${date}`);
let test = new storage1(input,date);
store(test);
li.appendChild(a);
a.appendChild(t);
document.getElementById("myList").appendChild(li).appendChild(a);
li.appendChild(button1);
li.appendChild(button2);
}
}
In this function I change their background color when i click on list element:
let list = document.querySelector('ul');
list.addEventListener('click', function(ev) {
if (ev.target.tagName === 'LI') {
ev.target.classList.toggle('checked');
}
}, false);
but i have no idea how to display buttons now
Change the display:
button1.style.display = "inline";
or remove the class:
button1.classList.remove("BtnEdit");
Related
For some reason when I try to do this event, it allows for only one letter in the text input. I tried searching for an answer and couldn't figure it out, can someone help me?
let button = document.getElementById("button");
let input = document.getElementById("userInput");
let ul = document.getElementById("list");
input.addEventListener("keypress", function(e){
if(e.keyCode == 13){
let li = document.createElement("li");
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)}
input.value = "";
}
);
There is another event, but this one works perfectly when alone and there is no text limit
button.addEventListener("click", function(){
let li = document.createElement("li");
if(input.value.length > 0){
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)}
input.value = "";
}
);
It happens because everytime you press a key it is setting the input.value to be empty. You may want to move the closing bracket to be after the input.value = "";. Like so:
let button = document.getElementById("button");
let input = document.getElementById("userInput");
let ul = document.getElementById("list");
input.addEventListener("keypress", function(e){
if(e.keyCode == 13){
let li = document.createElement("li");
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)
input.value = "";
}
}
As others have alluded to, input.value = ""; was emptying your input on each keypress event and you needed to move it inside of your if condition.
It seems like you realized the issue but here is a working snippet using your code:
let button = document.getElementById("button");
let input = document.getElementById("userInput");
let ul = document.getElementById("list");
input.addEventListener("keypress", function(e) {
if (e.keyCode == 13) {
let li = document.createElement("li");
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)
input.value = "";
}
}
);
button.addEventListener("click", function() {
let li = document.createElement("li");
if (input.value.length > 0) {
li.appendChild(document.createTextNode(input.value))
ul.appendChild(li)
}
input.value = "";
}
);
<button id="button">button</button><input id="userInput"></input><br/>
<ul id="list"></ul>
I have a list of items like a todo list and i have a search input where i want users to search through the list'
I am using the keyup event and if input matches i am trying to use css to set the matched li to display:'' while the list items that do not match i want to set display:none.
so far i am able to console.log my results but cant effect changes to my li list as the css to set display none doesn't work.
here is my code below.
const Ul = document.querySelector('.clipBoard');
const search = document.querySelector('.search');
array.forEach((item) => {
let button = document.createElement('button');
button.className =
'list-group-item buttonLi';
button.innerText += item;
Ul.appendChild(button);
//Search function
search.addEventListener('keyup', () => {
let filterValue = search.value;
const li = Ul.querySelectorAll('.buttonLi');
for (let i = 0; i < li.length; i++) {
let List = li[i];
if (List.innerHTML.indexOf(filterValue) > -1) {
console.log(li[i].innerHTML);
li[i].style.display = '';
} else {
li[i].style.display = 'none';
}
}
});
I would suggest you to assign an id to each element using the index at that level:
array.forEach((item, INDEX) => {
let button = document.createElement('button');
var id = 'el-'+INDEX
button.setAttribute("id", id);
button.setAttribute("class", "list-group-item buttonLi");
button.innerText += item;
});
Then on your search function use that id to hide the elements
search.addEventListener('keyup', () => {
let filterValue = search.value;
const li = Ul.querySelectorAll('.buttonLi');
for (let i = 0; i < li.length; i++) {
let List = li[i];
if (List.innerHTML.indexOf(filterValue) > -1) {
console.log(li[i].innerHTML);
// something like that
var idToShow = '#el-'+i;
document.querySelector(idToShow).style.display = 'block';
} else {
// something like that
var idToHide = '#el-'+i;
document.querySelector(idToHide).style.display = 'none';
}
}
});
I did not test this code, just trying to point you to an eventual solution!
You could also do the filtering on your array then for each search you re-render your list!
function createElement(){
const input = document.getElementById("input");
const ul = document.getElementById("ul");
const li = document.createElement("li");
const div = document.createElement("div");
div.innerText = input.value;
const btn = document.createElement("button");
btn.innerText = "add 2";
li.appendChild(div);
li.appendChild(btn);
ul.appendChild(li);
btn.onclick = () => {
let num = parseInt(div.innerText);
num = num + 2;
const roundednum = num.toFixed(2);
div.innerText = roundednum;
btnCLicked = true;
}
}
document.getElementById("btn").addEventListener("click", createElement);
<input type="number" id="input">
<ul id="ul"></ul>
<button id="btn">click me</button>
i have this simple code above that creates some elements, and it will add 2 to the number in the div when button inside the <li> is clicked, which works perfectly
now i want to subtract 2 from the number when button is clicked the second time, so first click will add 2, second click will subtract 2
so i come up with this code which uses a boolean to add and subtract the number which works
let btnCLicked = false;
function createElement(){
const input = document.getElementById("input");
const ul = document.getElementById("ul");
const li = document.createElement("li");
const div = document.createElement("div");
div.innerText = input.value;
const btn = document.createElement("button");
btn.innerText = "add 2";
li.appendChild(div);
li.appendChild(btn);
ul.appendChild(li);
btn.onclick = () => {
if (btnCLicked === false) {
let num = parseInt(div.innerText);
num = num + 2;
const roundednum = num.toFixed(2);
div.innerText = roundednum;
btnCLicked = true;
}else if (btnCLicked === true) {
let num = parseInt(div.innerText);
num = num - 2;
const roundednum = num.toFixed(2);
div.innerText = roundednum;
btnCLicked = false;
}
}
}
document.getElementById("btn").addEventListener("click", createElement);
<input type="number" id="input">
<ul id="ul"></ul>
<button id="btn">click me</button>
but now the problem is that when i create an <li>, and click the button inside to add 2 to the number, btnClicked is now set to true.
so when i create another element and click the button for the first time it will subtract the number because btnClicked is true, which is what i dont want, i want the first click to add and subtract on the second click
how do i solve that problem? im thinking about something like making the boolean only inside each li so each li has an own boolean and it will not effect other elements but idk lol i have no other idea
Move the let btnCLicked = false; into the function. Each invocation of createElement() will create a [closure`]1 since it's child function (click handler) is using variables from parents scope:
const input = document.getElementById("input");
const ul = document.getElementById("ul");
function createElement() {
let btnCLicked = false;
const li = document.createElement("li");
const div = document.createElement("div");
const btn = document.createElement("button");
div.innerText = input.value || 0;
btn.innerText = "add 2";
li.appendChild(div);
li.appendChild(btn);
ul.appendChild(li);
btn.onclick = () => {
let num = Number(div.innerText);
if (btnCLicked === false) {
num += 2;
} else {
num -= 2;
}
div.innerText = num;
btnCLicked = !btnCLicked;
}
}
document.getElementById("btn").addEventListener("click", createElement);
<input type="number" id="input">
<ul id="ul"></ul>
<button id="btn">click me</button>
Another solution: use event delegation and use a data-attribute to track the last action (add or subtract):
document.addEventListener("click", handle);
function createElement() {
document.querySelector("#ul").insertAdjacentHTML("beforeend", `
<li>
<div>${(+document.querySelector("#input").value).toFixed(2)}</div>
<button data-action="add">2</button>
</li>`);
}
function handle(evt) {
const origin = evt.target;
if (origin.id === "btn") {
return createElement();
}
if (origin.dataset.action) {
return addOrSubtract2(origin);
}
}
function addOrSubtract2(fromBttn) {
const parentLi = fromBttn.closest("li");
const add = fromBttn.dataset.action === "add";
const num = +(parentLi.querySelector("div").textContent) + (add ? 2 : -2);
fromBttn.dataset.action = add ? "subtract" : "add";
parentLi.querySelector("div").textContent = num.toFixed(2);
}
[data-action]:before {
content: attr(data-action)' ';
}
<input type="number" id="input" value=0 step="0.1">
<button id="btn">create new</button>
<ul id="ul"></ul>
I want the List-Style-Image to be Apppear while using "flex" and have space between "bin" image and List-Style-Image . I dont know why every time i apply the flex-property on "Li" the image dissapear's
let input = document.querySelector("#textFeild");
let button = document.querySelector("#button");
let toDoContainer = document.querySelector("#toDoContainer");
let ul = toDoContainer.querySelector("ul");
// Adding Event on Button
button.addEventListener("click", function(){
let li = document.createElement('li');
li.style.listStyleImage = "url('assets/icons/checkbox.png')";
li.style.display = "list-item";
li.innerText = input.value;
li.style.fontSize = "30px";
li.style.borderBottom = "1px solid #f2f1f1";
li.style.padding = "20px";
li.style.display = "flex"; //problem is here
li.style.justifyContent = "space-between";
ul.appendChild(li);
let bin = document.createElement("IMG");
bin.setAttribute("src", "assets/icons/bin.png");
bin.setAttribute("width", "30");
bin.style.marginLeft = "auto";
li.appendChild(bin);
input.value = ""; //It will Clear the Feild for next Value.
//We write Event-listner on Paragrahs (Nested) Here Because of "let" Block-Scope.
li.addEventListener("click", function(){
li.style.textDecoration = "line-through";
li.style.listStyleImage = "url('assets/icons/checkmark.png')";
})
bin.addEventListener("click", function(){
ul.removeChild(li);
})
})
You are setting li.style.display = "list-item"; and then rewriting it to flex. Property listStyleImage is for elements with display: list-item
I'm currently building off Wes Bos Javascript 30 project.
Turned the project into a to-do app. And I can't figure out how to use the shift-clicking on newly created checkboxes using vanilla javascript.
Any insight on how to do this?
const addBtn = document.querySelector('.addBtn');
const myInput = document.getElementById('myInput');
const toDo = document.querySelector('.toDo-container');
const checkbox = document.querySelectorAll('.toDo-container input[type=checkbox]');
addBtn.addEventListener('click', newElement);
myInput.addEventListener("keyup", function(e){
if(e.keyCode === 13){
e.preventDefault()
newElement() }
});
// Create a new item when clicking on the "Add" button
function newElement(){
let div = document.createElement('div');
let input = document.createElement('input');
let inputValue = document.getElementById('myInput').value;
let textNode = document.createTextNode(inputValue);
let p = document.createElement('p');
div.className = "item";
input.type = "checkbox";
p.appendChild(textNode);
div.appendChild(input);
div.appendChild(p);
toDo.appendChild(div);
if(inputValue !== ""){
document.getElementById("myInput").value = "";
}
}
// Shift Clicking Checkboxes.
let lastChecked;
function shiftClick(e){
let inBetween = false;
if(e.shiftKey && this.checked){
checkbox.forEach(box => {
if(box === this || box === lastChecked){
inBetween = !inBetween
}
if(inBetween){
box.checked = true;
}
});
}
lastChecked = this;
}
checkbox.forEach(box => box.addEventListener('click', shiftClick));
https://codepen.io/iameddieyayaya/pen/XGWaQN?editors=1011
Thanks a ton!
Eddie G.
You can set a flag when the shift key is pressed and reset it when the key is released. Then your click listener can just act conditionally based on the state of the flag. (I don't know if focusing the whole container as I've done here is the best way to ensure that you don't fail to notice any keystrokes, but it works.)
const container = document.getElementById("container");
const box = document.getElementById("box");
let shiftIsDown = false;
container.addEventListener("keydown", setShiftFlag);
container.addEventListener("keyup", setShiftFlag);
box.addEventListener("click", handleBoxClick);
container.focus();
function setShiftFlag(event){
if(event.code == "ShiftLeft" || event.code == "ShiftRight"){
if(event.type == "keydown"){
shiftIsDown = true;
}
else if(event.type == "keyup"){
shiftIsDown = false;
}
}
}
function handleBoxClick(){
if(shiftIsDown){
console.log("shift-click");
}
else{
console.log("click");
}
}
body{ height: 100px; }
#container{ width: 100%; height: 100%; }
<body>
<div id="container" tabindex="0">
<input type="checkbox" id="box" />
</div>
</body>