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>
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>
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");
I'm really new to the contenteditable variable for html and so I want to dig your brains a bit :).
I want to allow users to edit content if they wish to but I'm stuck in the cancel btn option.
How can I retain the previous content if a user clicks the cancel btn? I've been looking at the documentation but struggle to find something. Please see the code below:
const cancelBtn = document.getElementById('cancel-btn');
console.log(editBtn);
function editable() {
const h3 = document.querySelector('h3');
const h4 = document.querySelector('h4');
const p = document.querySelector('p');
h3.className = 'edit';
h4.className = 'edit';
p.className = 'edit';
h3.contentEditable = true;
h4.contentEditable = true;
p.contentEditable = true;
addSaveBtn();
}
function cancelEdit() {
const h3 = document.querySelector('h3');
const h4 = document.querySelector('h4');
const p = document.querySelector('p');
h3.classList.remove('edit');
h4.classList.remove('edit');
p.classList.remove('edit');
h3.contentEditable = false;
h4.contentEditable = false;
p.contentEditable = false;
removeSaveBtn();
}
function addSaveBtn() {
const cardAccess = document.querySelector('.card');
const saveBtn = document.createElement('button');
saveBtn.id = 'edit-save-btn';
saveBtn.textContent = 'Save';
if (document.getElementById('edit-save-btn')) {
return;
} else {
cardAccess.insertAdjacentElement('beforeend', saveBtn);
}
saveBtn.addEventListener('click', () => {
const h3 = document.querySelector('h3');
const h4 = document.querySelector('h4');
const p = document.querySelector('p');
h3.classList.remove('edit');
h4.classList.remove('edit');
p.classList.remove('edit');
h3.contentEditable = false;
h4.contentEditable = false;
p.contentEditable = false;
removeSaveBtn();
});
}
function removeSaveBtn() {
if (!document.getElementById('edit-save-btn')) {
return;
} else {
document.getElementById('edit-save-btn').remove();
}
}
editBtn.addEventListener('click', editable);
cancelBtn.addEventListener('click', cancelEdit);```
Edit:
To add a cancel button:
Create a variable that stores the innerHTML when save was pressed.
Set the innerHTML of the contenteditable element to this variable when the cancel button is pressed.
Full Example:
// Set up the variable
var savedText = content.innerHTML;
save.onclick = ()=>{
// store the current content in savedText
savedText = content.innerHTML;
}
cancel.onclick = ()=>{
// set the new html content to what was stored
content.innerHTML = savedText;
}
<div id="content" contenteditable="true"><h1>Edit Me!</h1></div>
<button id="save">Save</button>
<button id="cancel">Cancel</button>
The contentEditable property takes a string, so you probably want something like this:
function cancelEdit() {
const h3 = document.querySelector('h3');
const h4 = document.querySelector('h4');
const p = document.querySelector('p');
h3.classList.remove('edit');
h4.classList.remove('edit');
p.classList.remove('edit');
h3.contentEditable = "false";
h4.contentEditable = "false";
p.contentEditable = "false";
removeSaveBtn();
}
function editable() {
const h3 = document.querySelector('h3');
const h4 = document.querySelector('h4');
const p = document.querySelector('p');
h3.className = 'edit';
h4.className = 'edit';
p.className = 'edit';
h3.contentEditable = "true";
h4.contentEditable = "true";
p.contentEditable = "true";
addSaveBtn();
}
Example with toggling:
toggle.onclick = ()=>{
content.contentEditable = (!content.isContentEditable).toString();
toggle.textContent = content.isContentEditable ? "Turn Editability Off" : "Turn editability On"
}
<div id="content" contenteditable="true"><h1>Edit Me!</h1></div>
<button id="toggle">Turn Editability Off</button>
I'm working on a to-do list project and when creating a new li I would like it to start with a span containing a "X". I wrote the code below, but instead of a span I get "[object HTMLSpanElement]". Anybody knows how to fix this? Thank you!
var enterItem = document.querySelectorAll("input");
var todoList = document.getElementById("todo-list");
for (var i = 0; i < enterItem.length; i++) {
enterItem[i].addEventListener("keypress", function(key) {
if(key.which === 13){
var newLi = document.createElement("li");
var span = document.createElement("span");
var newItem = this.value;
span.textContent = "X";
newLi.appendChild(document.createTextNode(span + " " + newItem));
todoList.appendChild(newLi);
this.value = "";
}
});
}
You are trying to add an html element in a textNode so it triggers the toString of the element
You need
const todoList = document.getElementById("todo-list");
document.getElementById("inputContainer").addEventListener("keypress", function(e) {
const tgt = e.target;
if (tgt.type === "text" && e.which === 13) {
let newLi = document.createElement("li");
let span = document.createElement("span");
span.classList.add("remove");
let newItem = tgt.value;
span.textContent = "X";
newLi.appendChild(span)
newLi.appendChild(document.createTextNode(" " + newItem));
todoList.appendChild(newLi);
tgt.value = "";
}
});
document.getElementById("todo-list").addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("remove")) {
tgt.closest("li").remove();
}
})
<div id="inputContainer">
<input type="text" />
</div>
<ul id="todo-list"></ul>
Sorry, I am not really good with JS.
The code is essentially the user double clicks on the text, textbox appears, changes text, and saves a new value. However, I want the user to be able to also click enter to save the new value.
In addition, if possible, to have a dedicated "Save" button to save the new value and "discard" to keep the old value.
Also, if I double click many times, the text appears as "(input type="text")". Is there a way to remove that?
Please help if you can.
The HTML + JS code
<html>
<head>
<script type="text/javascript">
window.onload = function() {
var elements = getElementsByClassName('text-edit', '*', document);
for(var i = 0; i < elements.length; i++) {
elements[i].ondblclick = function() {
this.setAttribute('oldText', this.innerHTML); // not actually required. I use this just in case you want to cancel and set the original text back.
var textBox = document.createElement('INPUT');
textBox.setAttribute('type', 'text');
textBox.value = this.innerHTML;
textBox.onblur = function() {
var newValue = this.value;
this.parentNode.innerHTML = newValue;
}
this.innerHTML = '';
this.appendChild(textBox);
}
}(i);
}
function getElementsByClassName(className, tag, elm) {
var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
var tag = tag || "*";
var elm = elm || document;
var elements = (tag == "*" && elm.all) ? elm.all : elm.getElementsByTagName(tag);
var returnElements = [];
var current;
var length = elements.length;
for(var i = 0; i < length; i++) {
current = elements[i];
if(testClass.test(current.className)) {
returnElements.push(current);
}
}
return returnElements;
}
</script>
</head>
<div><span class="text-edit">Some text</span></div>
</html>
The snippet below allows you to modify the value of a textbox using save button or enter key and discarding any changes using cancel button.
<!-- HTML -->
<h1 id="editable">Lorem Ipsum</h1>
// JavaScript
window.onload = function(){
var h1 = document.getElementById('editable');
h1.onclick = function(){
var old = this;
var input = document.createElement("INPUT");
input.type = "text";
input.value = this.innerHTML;
input.onkeyup = function(e){
var code = (e.keyCode ? e.keyCode : e.which);
if(code == 13) {
old.innerHTML = input.value;
input.parentNode.replaceChild(old, input);
save.parentNode.removeChild(save);
cancel.parentNode.removeChild(cancel);
}
};
this.parentNode.replaceChild(input, this);
var save = document.createElement("INPUT");
save.type = "button";
save.value = "Save";
(function(old, input){
save.onclick = function(){
old.innerHTML = input.value;
input.parentNode.replaceChild(old, input);
this.parentNode.removeChild(this);
cancel.parentNode.removeChild(cancel);
};
})(old, input);
input.parentNode.insertBefore(save, input.nextSibling);
var cancel = document.createElement("INPUT");
cancel.type = "button";
cancel.value = "Cancel";
(function(old, input){
cancel.onclick = function(){
input.parentNode.replaceChild(old, input);
this.parentNode.removeChild(this);
save.parentNode.removeChild(save);
};
})(old, input);
input.parentNode.insertBefore(cancel, input.nextSibling);
};
};
Working jsBin