Why isn't the string.length updating? - javascript

This is my first piece of code js done on my own. I am trying to have an input field to add items to the list and then if you press the button to generate code it will collect all the checked items and copy the text into another div.
Basically, my question is around two variables:
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
Let say I have 4 items in the list. If I add a new item to the list I can see the list.length add this new item, it changes from 4 to 5.
But it doesn't happen with listCopy.length the value keeps being 4.
Why is it happening if lstCopy is inside of list?
How can I have listCopy updated too?
Here is my code:
const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = listUl.querySelectorAll('span');
const clonedCode = document.querySelector('.code p');
//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {
//Draggable
item.draggable = "true";
item.classList.add("list--item");
//Checkbox
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.name = "chkboxName1";
checkbox.value = "value";
checkbox.id = "id";
item.insertBefore(checkbox, item.childNodes[0] || null);
//Remove button
let remove = document.createElement('button');
remove.className = 'remove';
remove.textContent = 'x';
item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
attachItemListButton(list[i]);
}
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
let copyTextFromList = "";
for (let i = 0; i < listCopy.length; i += 1) {
if (listCopy[i].parentNode.querySelector("input:checked")) {
copyTextFromList += listCopy[i].textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
let li = document.createElement('li');
let span = document.createElement('span');
span.textContent = addItemInput.value;
listUl.appendChild(li);
li.appendChild(span);
attachItemListButton(li);
addItemInput.value = '';
});
//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
if (event.target.tagName == 'BUTTON') {
if (event.target.className == 'remove') {
let li = event.target.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
}
}
});
/* Google fonts */
#import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
/* Root */
:root {
--color-white: #fff;
--color-black: #2D3142;
--color-black-2: #0E1116;
--color-gray: #CEE5F2;
--color-gray-2: #ACCBE1;
--color-gray-3: #CEE5F2;
--color-green: #439775;
--color-blue: #4686CC;
}
body {
font-family: 'Heebo', sans-serif;
font-weight: 400;
font-size: 16px;
color: black;
}
h2 {
font-weight: 700;
font-size: 1.5rem;
}
h3 {
font-weight: 700;
font-size: 1.25rem;
}
button {
background: var(--color-blue);
padding: 5px 10px;
border-radius: 5px;
color: var(--color-white);
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
}
ul.list {
list-style-type: none;
padding: 0;
max-width: 300px;
}
.list button {
background: var(--color-black);
}
.list--item {
display: flex;
justify-content: space-between;
align-items: center;
width: auto;
margin: 5px auto;
padding: 5px;
cursor: move;
background: var(--color-gray);
border-radius: 5px;
}
.list--item.draggingElement {
opacity: 0.4;
}
.list--item.over {
border-top: 3px solid var(--color-green);
}
button.remove {
margin: auto 0 auto auto;
}
input#id {
margin: auto 5px auto 0;
}
.button-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
max-width: 300px;
}
.button-wrapper .addItemInput {
width: 63%;
border-radius: 5px 0 0 5px;
}
.button-wrapper .addItemButton {
width: 35%;
border-radius: 0 5px 5px 0;
}
.button-wrapper .generateCode {
width: 100%;
background: var(--color-green);
margin-top: 5px;
}
.code p {
background: var(--color-gray); padding: 5px;
border: 1px solid var(--color-gray-2);
min-height: 20px;
font-weight: 300;
}
<ul class="list">
<li><span>Header</span></li>
<li><span>Hero</span></li>
<li><span>Intro</span></li>
<li><span>Footer</span></li>
</ul>
<div class="button-wrapper">
<input type="text" class="addItemInput" placeholder="Item description">
<button class="addItemButton">Add item</button>
<button class="generateCode">Generate code</button>
</div>
<div class="code">
<h2>Code</h2>
<p></p>
</div>

There are two variants of NodeList, live and non-live ones. querySelectorAll returns a static NodeList that is not live. .children returns a live one (technically it returns an HTMLCollection but you can ignore this distinction for now).
To make listCopy be live as well, you could use listUl.getElementsByTagName('span')…
To select elements by their classes, use getElementsByClassName. There is no way (that I know of) to get a live collection with CSS or XPath (i.e. more complex) queries, though.

The problem is that const listCopy = listUl.querySelectorAll('span'); is initiated with the span array from the beginning.
In order to get updated list
const listCopy = listUl.querySelectorAll('span'); will be let listCopy = listUl.querySelectorAll('span'); and in your function
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
// add the following line - in this way you will select the span from the updated list
listCopy = listUl.querySelectorAll('span');
let copyTextFromList = "";
for (let i = 0; i < listCopy.length; i += 1) {
if (listCopy[i].parentNode.querySelector("input:checked")) {
copyTextFromList += listCopy[i].textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});

if you want to use querySelectorAll, this maybe help. with this every time you check the length it recalculates and returns the value. Symbol.iterator helps you to manipulate for...of loops.
const addItemInput = document.querySelector('.addItemInput');
const addItemButton = document.querySelector('.addItemButton');
const copyText = document.querySelector('.generateCode');
const listUl = document.querySelector('.list');
const list = listUl.children;
const listCopy = {
get length() {
return listUl.querySelectorAll('span').length
},
*[Symbol.iterator]() {
let i = 0;
const l = listUl.querySelectorAll('span');
while( i < l.length ) {
yield l[i];
i++;
}
}
};
const clonedCode = document.querySelector('.code p');
//FUNCTION: Generate value/items = Draggable, Checkbox, Remove button
const attachItemListButton = (item) => {
//Draggable
item.draggable = "true";
item.classList.add("list--item");
//Checkbox
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'checkbox';
checkbox.name = "chkboxName1";
checkbox.value = "value";
checkbox.id = "id";
item.insertBefore(checkbox, item.childNodes[0] || null);
//Remove button
let remove = document.createElement('button');
remove.className = 'remove';
remove.textContent = 'x';
item.appendChild(remove);
};
for (let i = 0; i < list.length; i += 1) {
attachItemListButton(list[i]);
}
//Cloning code if there are checked items
copyText.addEventListener('click', () => {
let copyTextFromList = "";
for (let item of listCopy) {
if (item.parentNode.querySelector("input:checked")) {
copyTextFromList += item.textContent + ',';
}
}
clonedCode.innerHTML = copyTextFromList;
});
//Add item from the input field to the list
addItemButton.addEventListener('click', () => {
let li = document.createElement('li');
let span = document.createElement('span');
span.textContent = addItemInput.value;
listUl.appendChild(li);
li.appendChild(span);
attachItemListButton(li);
addItemInput.value = '';
});
//FUNCTION: Remove button
listUl.addEventListener('click', (event) => {
if (event.target.tagName == 'BUTTON') {
if (event.target.className == 'remove') {
let li = event.target.parentNode;
let ul = li.parentNode;
ul.removeChild(li);
}
}
});
/* Google fonts */
#import url('https://fonts.googleapis.com/css?family=Heebo:300,400,700');
/* Root */
:root {
--color-white: #fff;
--color-black: #2D3142;
--color-black-2: #0E1116;
--color-gray: #CEE5F2;
--color-gray-2: #ACCBE1;
--color-gray-3: #CEE5F2;
--color-green: #439775;
--color-blue: #4686CC;
}
body {
font-family: 'Heebo', sans-serif;
font-weight: 400;
font-size: 16px;
color: black;
}
h2 {
font-weight: 700;
font-size: 1.5rem;
}
h3 {
font-weight: 700;
font-size: 1.25rem;
}
button {
background: var(--color-blue);
padding: 5px 10px;
border-radius: 5px;
color: var(--color-white);
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-drag: element;
-webkit-user-drag: element;
}
ul.list {
list-style-type: none;
padding: 0;
max-width: 300px;
}
.list button {
background: var(--color-black);
}
.list--item {
display: flex;
justify-content: space-between;
align-items: center;
width: auto;
margin: 5px auto;
padding: 5px;
cursor: move;
background: var(--color-gray);
border-radius: 5px;
}
.list--item.draggingElement {
opacity: 0.4;
}
.list--item.over {
border-top: 3px solid var(--color-green);
}
button.remove {
margin: auto 0 auto auto;
}
input#id {
margin: auto 5px auto 0;
}
.button-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
max-width: 300px;
}
.button-wrapper .addItemInput {
width: 63%;
border-radius: 5px 0 0 5px;
}
.button-wrapper .addItemButton {
width: 35%;
border-radius: 0 5px 5px 0;
}
.button-wrapper .generateCode {
width: 100%;
background: var(--color-green);
margin-top: 5px;
}
.code p {
background: var(--color-gray); padding: 5px;
border: 1px solid var(--color-gray-2);
min-height: 20px;
font-weight: 300;
}
<ul class="list">
<li><span>Header</span></li>
<li><span>Hero</span></li>
<li><span>Intro</span></li>
<li><span>Footer</span></li>
</ul>
<div class="button-wrapper">
<input type="text" class="addItemInput" placeholder="Item description">
<button class="addItemButton">Add item</button>
<button class="generateCode">Generate code</button>
</div>
<div class="code">
<h2>Code</h2>
<p></p>
</div>

Related

onclick event not picking up className elements to append - showing error

I am not sure why my code is not picking up my selections and appending then to my array when the submit button is clicked. I am getting the following error...
"modals.js:103 Uncaught TypeError: Cannot read properties of null (reading 'length') at submit_button.onclick"
My code adds 'button focus' to the className when selected.
I want to take those selections and append them to my an array.
For some reason it does not detect any elements with the className of '.btn.button-focus'.
Any ideas?
var container = document.getElementById('my_dataviz');
var array = ["One", "Two", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten"
]
let identifier = 0;
let SelectCount = 0;
array.forEach(element => {
const button = document.createElement("button");
button.className = "btn";
button.id = element;
button.value = element;
button.type = "button";
const text = document.createTextNode(element);
button.appendChild(text);
container.appendChild(button);
});
let btn = document.getElementsByClassName("btn");
for (let i = 0; i < btn.length; i++) {
(function(index) {
btn[index].addEventListener("click", function() {
console.log("Clicked Button: " + index);
let isPresent = false;
this.classList.forEach(function(e, i) {
if (e == "button-focus") {
isPresent = true;
} else {
isPresent = false;
}
});
if (isPresent) {
this.classList.remove("button-focus");
SelectCount -= 1;
document.querySelectorAll('.btn').forEach(item => {
if (!item.classList.value.includes('button-focus')) item.disabled = false
})
} else {
this.classList.add("button-focus");
SelectCount += 1;
if (SelectCount > 2) {
document.querySelectorAll('.btn').forEach(item => {
if (!item.classList.value.includes('button-focus')) item.disabled = true
})
}
}
})
})(i)
}
const dataResults = []
let results = document.querySelector('.btn.button-focus');
let submit_button = document.querySelector('.modal-btn');
submit_button.onclick = function() {
for (let i = 0; i < results.length; ++i) {
dataResults.push(results)
console.log(results)
}
}
:root {
--primary_orange: #fea501;
}
.my_dataviz {
width: auto;
height: auto;
margin-top: 15px;
margin-bottom: 15px;
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: space-evenly;
}
.my_dataviz button {
font-family: "walkway";
font-size: 16px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
width: 130px;
height: 25px;
background-color: Transparent;
-webkit-tap-highlight-color: transparent;
background-repeat:no-repeat;
border: none;
letter-spacing: 1.6px;
margin: 10px;
border: 1px solid transparent;
}
.my_dataviz button:hover {
box-sizing: border-box;
background-color: var(--primary_orange);
color: var(--dark);
font-weight: bold;
border: 1px solid #000;
border-radius: 5px;
cursor: pointer;
/*box-shadow: var(--shadow);*/
}
.btn.button-focus {
background-color: var(--primary_orange);
color: var(--dark);
font-weight: bold;
border: 1px solid #000;
border-radius: 5px;
}
.modal-footer {
display: flex;
flex-wrap: wrap;
justify-content: center;
height: 50px;
align-items: center;
text-align: center;
background: var(--primary_med);
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
.modal-footer .modal-btn {
font-family: "walkway";
font-size: 16px;
font-weight: bold;
width: 100px;
height: 28px;
border-radius: 5px;
align-items: center;
letter-spacing: 1.6px;
box-shadow: var(--shadow);
}
<div class="my_dataviz" id="my_dataviz">
</div>
<div class="modal-footer">
<input class="modal-btn" type="button" value="Select it" />
</div>
It should run querySelector when the user presses the submit button.
const dataResults = []
let results = document.querySelector('.btn.button-focus'); // remove this line
let submit_button = document.querySelector('.modal-btn');
submit_button.onclick = function() {
dataResults = document.querySelectorAll('.btn.button-focus') // Edit
console.log(dataResults)
}
}
submit_button.onclick = function() {
if(results == null) return;
for (let i = 0; i < results.length; ++i) {
dataResults.push(results)
console.log(results)
}
}
querySelector returns null if it didn't find wanted elements.
But what you want anyways is change querySelector to querySelectorAll and use this code then:
submit_button.onclick = function() {
if(results.length == 0) return;
for (let i = 0; i < results.length; i++) {
dataResults.push(results[i])
console.log(results[i])
}
}
(I made multiple changes to your code which changed the functionality according to what I think you wanted to do (I didn't read what is your purpose in the code))

JS todo list item checked, and add item

I am aiming to create a JS todo list similar to https://www.w3schools.com/howto/howto_js_todolist.asp
I have created the basic structure of my todo list application and the function of the close buttons.
These are working well, but I have a problem with adding new todo list items and checking and unchecking todo items.
I'm not sure if I'm using the classlist toggle property well, and also cannot figure why the add button doesn't work at all.
var todoitemlist = document.getElementsByClassName('todo-item');
var i;
for (i = 0; i < todoitemlist.length; i++) {
var span = document.createElement("SPAN");
span.innerHTML = "Close";
span.className = "closebutton";
todoitemlist[i].appendChild(span);
}
var close = document.getElementsByClassName("closebutton");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var listitem = this.parentElement;
listitem.style.display = "none";
}
}
var todoitemlistx = document.getElementsByClassName('todo-item');
//checked element
var i;
for (i = 0; i < todoitemlistx.length; i++) {
todoitemlistx[i].onclick = function(ev) {
ev.style.backgroundColor = "red";
ev.classList.toggle("todo-item-checked");
}
}
//add another list item
function add() {
var listitem = document.createElement("LI");
listitem.className = "todo-item";
var text = document.getElementById('todoinput').value;
var myul = getElementById('todo-list');
var t = document.createTextNode(text);
listitem.appendChild(t);
myul.appendChild(listitem);
var span = document.createElement("SPAN");
span.innerHTML = "Close";
span.className = "closebutton";
listitem[i].appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
* {
box-sizing: border-box;
}
body {
text-align: center;
margin: 0;
padding: 0;
background-color: #dbf9fc;
font-family: Arial, Helvetica, sans-serif;
color: rgba(0, 27, 39);
}
#todoinput {
margin: 5px;
padding: 5px;
width: 65%;
}
#add-button {
padding: 5px;
margin: 5px;
width: 5%;
background-color: rgba(0, 27, 39);
color: #dbf9fc;
border: none;
border-radius: 5px;
height: 1fr;
cursor: pointer;
}
#add-button:hover {
background-color: black;
}
#todo-list {
display: inline-block;
margin: 0;
padding: 0;
list-style: none;
width: 70%;
}
.todo-item {
position: relative;
display: flex;
justify-content: flex-start;
background-color: white;
border: 2px solid black;
padding: 5px;
margin: 5px;
}
.closebutton {
cursor: pointer;
justify-self: flex-end;
background-color: #e6772d;
position: absolute;
right: 0;
top: 0;
color: white;
float: right;
padding: 5px;
width: 30%;
margin: 0;
}
.closebutton:hover {
background-color: #c46526;
}
.todo-item-checked {
position: relative;
display: flex;
justify-content: flex-start;
background-color: rgb(187, 187, 187);
border: 2px solid black;
padding: 5px;
margin: 5px;
text-decoration: line-through;
}
.black {
background-color: black;
}
<main class="centered">
<h1>ToDo List JS</h1>
<h3>js project</h3>
<form action="">
<input type="text" name="" id="todoinput" placeholder="Enter the activity you've wented to do">
<input type="button" value="Add" id="add-button" onclick="add()">
</form>
<ul id="todo-list">
<li class="todo-item">
Hit the lights
</li>
<li class="todo-item">
Hit the lights
</li>
<li class="todo-item">
Hit the lights
</li>
<li class="todo-item-checked todo-item">
Hit the lights
</li>
</ul>
</main>
I remember what it was like starting development and how hard it could be, so I persevered with this.
I thought it would be a few small changes but it turned into a massive rewrite.
Una grande padulo, as the Italians like to say.
I hope you can or try to understand what I did here.
The big lesson would be, don't write the same code twice, put it in a separate function.
So this seems to work.
Let me know if it doesn't.
var todoitemlist=document.getElementsByClassName('todo-item');
for(var i=0;i<todoitemlist.length;i++)
{
myawesomeclosebutton(todoitemlist[i]);
todoitemlist[i].addEventListener('click',myawesomebackground);
}
function myawesomeclosebutton(myawesomeitem)
{
var span=document.createElement('span');
span.innerHTML='Close';
span.className='closebutton';
span.addEventListener('click',myawesomecloseevent);
myawesomeitem.appendChild(span);
}
function myawesomebackground(ev)
{
if(ev.target.style.backgroundColor!='red')
{
ev.target.style.backgroundColor='red';
}
else
{
ev.target.style.backgroundColor='transparent';
}
}
function myawesomecloseevent(event)
{
var div=event.target.parentElement;
div.style.display='none';
}
function add()
{
var listitem=document.createElement('li');
listitem.className='todo-item';
var myawesomeinput=document.getElementById('todoinput');
var text=myawesomeinput.value;
var myul=document.getElementById('todo-list');
var t=document.createTextNode(text);
listitem.appendChild(t);
myul.appendChild(listitem);
listitem.addEventListener('click',myawesomebackground);
myawesomeclosebutton(listitem);
myawesomeinput.value='';
}

Move li items on click between lists does not work properly

I have to lists and am using a jquery function to move items from one list (id="columns")to the other (id="columns1") when I click on the items in the first list (id="columns").
That part of it works fine, but when I add a new item in the first list (id="columns"), the previously moved items show up in the first list (id="columns").
Is there a way to prevent the moved items to show up in the first list? Is there a way to do it with vanilla js or do I need to use jquery?
This is all part of an to do list app I am creating where you could add tasks, remove them, click on the task to consider it a finished task, etc.
// Create a "close" button and append it to each list item
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
// Click on a close button to hide the current list item
function closeEvent() {
var close = document.getElementsByClassName("close");
for (var i = 0; i < close.length; i++) {
close[i].onclick = function () {
var div = this.parentElement;
div.style.display = "none";
renderGraph();
}
}
}
// Add a "checked" symbol when clicking on a list item
var list = document.querySelector('ul');
list.addEventListener('click', function (ev) {
if (ev.target.tagName !== 'LI') return;
ev.target.classList.toggle('checked');
renderGraph();
}, false);
// Create a new list item when clicking on the "Add" button
function newElement() {
var li = document.createElement("li");
li.className = "column";
li.draggable = "true";
// order according to time
li.setAttribute("data-time", document.getElementById("myInput1").value);
// order according to time
var inputValue = document.getElementById("myInput").value;
var inputValue1 = document.getElementById("myInput1").value;
var tine = document.getElementById("myInput1");
tine.dateTime = "6:00"
// inputValue2.datetime = "6:00";
var tt = document.createTextNode(inputValue1 + " - ");
li.appendChild(tt);
var t = document.createTextNode(inputValue);
li.appendChild(t);
if (inputValue === '') {
alert("You must write a task!");
} else {
document.getElementById("columns").appendChild(li);
// order according to time start
setTimeout(function () {
var sortItems = document.querySelectorAll("[data-time]");
var elemArray = Array.from(sortItems);
elemArray.sort(function (a, b) {
if (a.getAttribute('data-time') < b.getAttribute('data-time')) { return -1 } else { return 1 }
});
//
document.getElementById("columns").innerHTML = "";
elemArray.forEach(appendFunction);
function appendFunction(item, index) {
document.getElementById("columns").innerHTML += item.outerHTML;
}
afterUpdate();
});
// order according to time end
}
document.getElementById("myInput").value = "";
document.getElementById("myInput1").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function () {
var div = this.parentElement;
div.style.display = "none";
}
}
}
// Add tasks by pressing enter
// Get the input field
var input = document.getElementById("myInput");
// Execute a function when the user releases a key on the keyboard
input.addEventListener("keyup", function (event) {
// Number 13 is the "Enter" key on the keyboard
if (event.keyCode === 13) {
// Cancel the default action, if needed
event.preventDefault();
// Trigger the button element with a click
document.getElementById("myBtn").click();
}
});
// //
// //
var btn = document.querySelector('.add');
var remove = document.querySelector('.column');
function dragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
};
function dragEnter(e) {
this.classList.add('over');
}
function dragLeave(e) {
e.stopPropagation();
this.classList.remove('over');
}
function dragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
return false;
}
function dragDrop(e) {
if (dragSrcEl != this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
closeEvent();
}
return false;
}
function dragEnd(e) {
var listItems = document.querySelectorAll('.column');
[].forEach.call(listItems, function (item) {
item.classList.remove('over');
});
this.style.opacity = '1';
}
function addEventsDragAndDrop(el) {
el.addEventListener('dragstart', dragStart, false);
el.addEventListener('dragenter', dragEnter, false);
el.addEventListener('dragover', dragOver, false);
el.addEventListener('dragleave', dragLeave, false);
el.addEventListener('drop', dragDrop, false);
el.addEventListener('dragend', dragEnd, false);
}
function addDragAndDrop() {
var listItems = document.querySelectorAll('.column');
listItems.forEach(addEventsDragAndDrop);
}
afterUpdate();
function afterUpdate() {
closeEvent();
addDragAndDrop();
renderGraph();
}
function addNewItem() {
var newItem = document.querySelector('.input').value;
if (newItem != '') {
document.querySelector('.input').value = '';
var li = document.createElement('li');
var attr = document.createAttribute('column');
var ul = document.querySelector('ul');
li.className = 'column';
attr.value = 'true';
li.setAttributeNode(attr);
li.appendChild(document.createTextNode(newItem));
ul.appendChild(li);
addEventsDragAndDrop(li);
}
}
#myInput1 {
width: 180px;
height: 36px;
margin-right: 10px;
/* margin-left: -40px; */
/* padding: 10px; */
/* color: red; */
/* box-sizing: border-box; */
/* background-color: blue; */
/* display: inline-block; */
}
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
/* Required to make elements draggable in old WebKit */
-khtml-user-drag: element;
-webkit-user-drag: element;
}
/* Include the padding and border in an element's total width and height */
* {
box-sizing: border-box;
font-family: 'Josefin Sans', sans-serif;
}
p {
font-weight: 300;
}
h1 {
font-weight: 300;
}
#x-text {
color: #f97350;
font-size: 1.5rem;
}
::placeholder{
color: #777d71;
}
#myInput1:before {
content:'Time:';
margin-right:.6em;
color: #777d71;
}
/* Remove margins and padding from the list */
ul {
margin: 0;
padding: 0;
list-style: none;
}
/* Style the list items */
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
background: #f7f6e7;
font-size: 18px;
transition: 0.2s;
color: rgb(94, 91, 91);
/* make the list items unselectable */
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* Set all odd list items to a different color (zebra-stripes) */
ul li:nth-child(odd) {
background: #dfddc5;
}
/* Darker background-color on hover */
ul li:hover {
background: rgb(207, 205, 205);
}
/* When clicked on, add a background color and strike out text */
ul li.checked {
background: #888;
color: #fff;
text-decoration: line-through;
}
/* Add a "checked" mark when clicked on */
ul li.checked::before {
content: '';
position: absolute;
border-color: #fff;
border-style: solid;
border-width: 0 2px 2px 0;
top: 10px;
left: 16px;
transform: rotate(45deg);
height: 15px;
width: 7px;
}
/* Style the close button */
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
color: #f97350;
/* font-size: 1.5rem; */
}
.close:hover {
background-color: #f97350;
color: white;
}
/* Style the header */
.header {
background-color: #777d71;
padding: 30px 40px;
color: white;
text-align: center;
}
/* Clear floats after the header */
.header:after {
content: "";
display: table;
clear: both;
}
/* Style the input */
input {
margin: 0;
border: none;
border-radius: 0;
width: 75%;
padding: 10px;
float: left;
font-size: 16px;
}
/* Style the "Add" button */
/* .addBtn {
padding: 10px;
width: 25%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
border-radius: 0;
} */
/* .addBtn:hover {
background-color: #bbb;
} */
#finished-tasks {
/* box-sizing: border-box; */
padding: 20px;
display: grid;
align-content: center;
justify-content: center;
background-color:#bbd38b ;
color: white;
margin-bottom: -20px;
margin-top: 40px;
}
#finished-tasks-p {
/* box-sizing: border-box; */
padding: 20px;
display: grid;
align-content: center;
justify-content: center;
background-color:#bbd38b ;
color: white;
margin-bottom: 0;
margin-top: 0;
}
/* #myChart{
margin-top: 50px;
width: 50vw;
height: 100px;
padding-left: 200px;
padding-right: 200px;
} */
/* canvas{
width:1000px !important;
height:auto !important;
margin: auto;
} */
#media only screen and (max-width: 855px){
input {
margin: 10px;
}
#myInput {
display: grid;
width:70vw;
/* align-content: center; */
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="myDIV" class="header">
<h1>My Daily Tasks</h1>
<p>Add a time and task then press enter. When finished task click on task bar</p>
<p>To delete task click on <span id="x-text">x</span> in the corner of task bar</p>
<input type="time" id="myInput1" value="06:00">
<input name="text" type="text" id="myInput" placeholder="My task...">
<span onclick="newElement()" class="addBtn" id="myBtn"></span>
</div>
<ul id="columns">
<!-- <li draggable="true" class="column">test</li>
<li draggable="true" class="column">test1</li> -->
<!-- <li class="column" draggable="true">w</li>
<li class="column" draggable="true">ff</li>
<li class="column" draggable="true">uuu</li> -->
</ul>
<ul id="columns2">
<h1 id="finished-tasks">finished Tasks</h1>
<p id="finished-tasks-p">Finished tasks would show up here once you have clicked on the task</p>
</ul>
<!-- adding a graph -->
<canvas id="myChart" width="400" height="400"></canvas>
<script src="/graph.js"></script>
<script src="/app.js"></script>
<!--
<div id="element"></div>
<script>
document.getElementById('element').innerHTML = 'Hi';
</script>-->
<script>
$("#columns").on('click', 'li', function () {
$(this).appendTo('#columns2');
});
$("#listC").on('click', 'li', function () {
$(this).appendTo('#listB');
});
</script>
Change your setTimeout call to this:
setTimeout(function () {
var sortItems = Array.from(document.querySelectorAll("[data-time]"))
.filter((item) => !item.classList.contains('checked'))
.sort(function (a, b) {
if (a.getAttribute('data-time') < b.getAttribute('data-time')) { return -1 } else { return 1 }
});
document.getElementById("columns").innerHTML = "";
sortItems.forEach(appendFunction);
function appendFunction(item, index) {
document.getElementById("columns").innerHTML += item.outerHTML;
}
afterUpdate();
});
The key passage is here:
.filter((item) => !item.classList.contains('checked'))
Before, you were selecting all of the items, even the ones that were already checked. This filters those out.
Here's a working JSFiddle you can experiment with. I had to add an event listener to the addBtn to get it to work on there, but your original script is fine when running from my local machine.

Javascript - Lists created through user input with a sort button

What I want: User types word into input bar -> user presses Add button -> word is added to two lists "unsortedUL" and "sortedUL" - > user presses Sort button -> the list "sortedUL" gets sorted by descending (z-a), while "unsortedUL" remains exactly how the user inputted it.
I cannot figure out how to get TWO lists while only ONE of them is sorted.
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
function newElement() {
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
if (inputValue === '') {
alert("You must write a word!");
} else {
document.getElementById("sortedUL").appendChild(li);
}
document.getElementById("myInput").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
function sortList() {
var list, i, switching, b, shouldSwitch;
list = document.getElementById("sortedUL");
switching = true;
while (switching) {
switching = false;
b = list.getElementsByTagName("LI");
for (i = 0; i < (b.length - 1); i++) {
shouldSwitch = false;
if (b[i].innerHTML.toLowerCase() < b[i + 1].innerHTML.toLowerCase()) {
shouldSwitch= true;
break;
}
}
if (shouldSwitch) {
b[i].parentNode.insertBefore(b[i + 1], b[i]);
switching = true;
}
}
}
document.getElementById("date").innerHTML = new Date().toDateString();
document.getElementById("time").innerHTML = new Date().toLocaleTimeString();
body {
margin: 0;
min-width: 250px;
background-color: green;
}
* {
box-sizing: border-box;
}
ul {
margin: 0;
padding: 0;
width: 100%;
float: right;
}
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
list-style-type: number;
background: #eee;
font-size: 18px;
transition: 0.2s;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.header {
background-color: green;
padding: 30px 40px;
color: white;
text-align: center;
}
.header:after {
content: "";
display: table;
clear: both;
}
input {
border: none;
width: 50%;
padding: 10px;
float: center;
font-size: 16px;
}
.addBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: right;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
.sortBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
<!DOCTYPE html>
<html>
<title>Assignment Two</title>
<body>
<h1 style="color:white;"align="center"id="date"></h1>
<h1 style="color:white;"align="center"id="time"></h1>
<div id="myDIV" class="header">
<h2 style="margin:5px">Enter a list of words</h2>
<input type="text" id="myInput" placeholder="Word...">
<span onclick="newElement()" class="addBtn">Add</span>
<span onclick="sortList()" class="sortBtn">Sort</span>
</div>
<ul id="sortedUL">
</ul>
<ul id="unsortedUL">
</ul>
</body>
</html>
You have to clone the HTML Node to append it twice.
Or create it twice like I did.
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
myNodelist[i].appendChild(span);
}
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
function newElement() {
if (inputValue === '') {
alert("You must write a word!");
} else {
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
document.getElementById("sortedUL").appendChild(li);
var li = document.createElement("li");
var inputValue = document.getElementById("myInput").value;
var t = document.createTextNode(inputValue);
li.appendChild(t);
document.getElementById("unsortedUL").appendChild(li);
}
document.getElementById("myInput").value = "";
var span = document.createElement("SPAN");
var txt = document.createTextNode("\u00D7");
span.className = "close";
span.appendChild(txt);
li.appendChild(span);
for (i = 0; i < close.length; i++) {
close[i].onclick = function() {
var div = this.parentElement;
div.style.display = "none";
}
}
}
function sortList() {
var list, i, switching, b, shouldSwitch;
list = document.getElementById("sortedUL");
switching = true;
while (switching) {
switching = false;
b = list.getElementsByTagName("LI");
for (i = 0; i < (b.length - 1); i++) {
shouldSwitch = false;
if (b[i].innerHTML.toLowerCase() < b[i + 1].innerHTML.toLowerCase()) {
shouldSwitch= true;
break;
}
}
if (shouldSwitch) {
b[i].parentNode.insertBefore(b[i + 1], b[i]);
switching = true;
}
}
}
document.getElementById("date").innerHTML = new Date().toDateString();
document.getElementById("time").innerHTML = new Date().toLocaleTimeString();
body {
margin: 0;
min-width: 250px;
background-color: green;
}
* {
box-sizing: border-box;
}
p {
font-size: 16px;
margin-left: 20px;
color: white;
text-transform: uppercase;
}
ul {
margin: 0 0 20px 0;
padding: 0;
width: 100%;
float: right;
}
ul li {
cursor: pointer;
position: relative;
padding: 12px 8px 12px 40px;
list-style-type: number;
background: #eee;
font-size: 18px;
transition: 0.2s;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.close {
position: absolute;
right: 0;
top: 0;
padding: 12px 16px 12px 16px;
}
.header {
background-color: green;
padding: 30px 40px;
color: white;
text-align: center;
}
.header:after {
content: "";
display: table;
clear: both;
}
input {
border: none;
width: 50%;
padding: 10px;
float: center;
font-size: 16px;
}
.addBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: right;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
.sortBtn {
padding: 10px;
width: 10%;
background: #d9d9d9;
color: #555;
float: left;
text-align: center;
font-size: 16px;
cursor: pointer;
transition: 0.3s;
}
<!DOCTYPE html>
<html>
<title>Assignment Two</title>
<body>
<h1 style="color:white;"align="center"id="date"></h1>
<h1 style="color:white;"align="center"id="time"></h1>
<div id="myDIV" class="header">
<h2 style="margin:5px">Enter a list of words</h2>
<input type="text" id="myInput" placeholder="Word...">
<span onclick="newElement()" class="addBtn">Add</span>
<span onclick="sortList()" class="sortBtn">Sort</span>
</div>
<p>Sorted</p>
<ul id="sortedUL">
</ul>
<p>Unsorted</p>
<ul id="unsortedUL">
</ul>
</body>
</html>
While you need list you can use Javascript Array
Here you can have two Arrays which would be SortedList and UnsortedList
I have declare both the list globally so that you can sort one list and keep one list without change
Refer The Below Code for the Work Flow
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form>
<div>
<input type="text" name="txtName" id="txtName"/>
<input type="button" value="Add" onclick="AddToList()"/>
<input type="button" value="Sort" onclick="SortList()"/>
</div>
</form>
</body>
</html>
<script>
var sortedList = [];
var unsortedList = [];
function AddToList() {
var data = document.getElementById("txtName").value;
sortedList.push(data);
unsortedList.push(data);
}
function SortList() {
sortedList.sort();
sortedList.reverse();
console.log(sortedList);
console.log(unsortedList);
}
</script>
Here I have created two buttons as you said
And Called a function to sort and other to add in the List.
As you said you need the Unsorted List to be as it is, So in the SortList() function we have printed sortedList and unsortedList Both two see a diffrence.
As expected sortedList will print the descending order data and unsortedList will print normal data.
You just need to insert it into both lists as each word is added, i.e. where you have:
document.getElementById("sortedUL").appendChild(li);
you should add a second line like this:
document.getElementById("unsortedUL").appendChild(li.cloneNode(true));
The node cloning might be what you were missing if you tried it before, otherwise it would move the same element and it ends up in only one list. The 'true' argument makes a deep copy so that the text node underneath it is copied as well.
Incidentally, this whole operation would be a lot easier with jQuery, it's the kind of DOM manipulation that the library was meant for. However people jump to jQuery so quickly and it's good that you are doing it with vanilla JavaScript.

removing the input text in the text field that matches the removed tab

In this example I made, since it uses keyup event, each input text (separated by comma) entered is converted into a tab. I want the input text to be deleted from the text field according to the tab I remove; for example, I enter "Item 1" but I suddenly change my mind and decide to remove the "Item 1" tab, the input text in the text field that has a string that matches the textContent of the removed tab should be automatically deleted from the text field.
var query = document.querySelector.bind(document);
query('#textfield').addEventListener('keyup', addTag);
function addTag(e) {
var evt = e.target;
if(evt.value) {
var items = evt.value.split(',');
if(items.length <= 10) {
evt.nextElementSibling.innerHTML = null;
for(var i = 0; i < items.length; i++) {
if(items[i].length > 0) {
var label = document.createElement('label'),
span = document.createElement('span');
label.className = 'tag';
label.textContent = items[i];
span.className = 'remove';
span.title = 'Remove';
span.textContent = 'x';
label.insertAdjacentElement('beforeend', span);
evt.nextElementSibling.appendChild(label);
span.addEventListener('click', function() {
var currentElement = this;
currentElement.parentNode.parentNode.removeChild(currentElement.parentNode);
})
}
}
}
} else {
evt.nextElementSibling.innerHTML = null;
}
}
section {
width: 100%;
height: 100vh;
background: orange;
display: flex;
align-items: center;
justify-content: center;
}
.container {
width: 50%;
}
input[name] {
width: 100%;
border: none;
border-radius: 1rem 1rem 0 0;
font: 1rem 'Arial', sans-serif;
padding: 1rem;
background: #272727;
color: orange;
box-shadow: inset 0 0 5px 0 orange;
}
input[name]::placeholder {
font: 0.9rem 'Arial', sans-serif;
opacity: 0.9;
}
.tags {
width: 100%;
height: 250px;
padding: 1rem;
background: #dfdfdf;
border-radius: 0 0 1rem 1rem;
box-shadow: 0 5px 25px 0px rgba(0,0,0,0.4);
position: relative;
}
.tags > label {
width: auto;
display: inline-block;
background: #272727;
color: orange;
font: 1.1rem 'Arial', sans-serif;
padding: 0.4rem 0.6rem;
border-radius: .2rem;
margin: 5px;
}
.tags > label > span {
font-size: 0.7rem;
margin-left: 10px;
position: relative;
bottom: 2px;
color: #ff4d4d;
cursor: pointer;
}
<section id="tags-input">
<div class="container">
<input type="text" name="items" id="textfield" placeholder="Enter any item, separated by comma(','). Maximum of 10" autofocus>
<div class="tags"></div>
</div>
</section>
How can I make that feature possible?
Replace the 'x' button listener with this one:
span.addEventListener('click', function () {
var text_field = document.getElementById("textfield");
var evt = this.parentNode;
var tags = text_field.value;
this.parentNode.removeChild(this); // remove the 'x' span so you can get the pure tag text with .innerHTML
var evname = evt.innerHTML;
var tags_array = tags.split(",");
var tag_position = tags_array.indexOf(evname);
if(tag_position > -1)
tags_array.splice(tag_position,1);
text_field.value = tags_array.join(',');
evt.parentNode.removeChild(evt);
})
// Coding this complexity in pure javascript when there is jQuery is ... like eating soup with a fork. You will get the job done, but it is dammn hard!

Categories

Resources