Save on localstorage appended checkbox state - javascript

I have this function:
function test() {
var a = document.getElementById('test');
var b = document.createElement('input');
b.type = 'checkbox';
b.addEventListener( 'change', function() {
if(this.checked) {
//do something and save the state (checked)
} else {
//do something else and save the state(not checked)
}
}
and I want to save the state of the checkbox on localstorage from the appended checkbox, what is the best way to do it?

so if you are appending multiple checkboxes and you want to probably set all of their data separately you are going to need to have a different id for each checkbox so when you append a new one I would increment the ids
//function that appends new checkbox
var i = 0;
function appendCheckBox(){
i++
checkBoxId = 'checkbox' + i;
document.getElementById('checkbox-container').innerHTML = `<input type="checkbox" id="${checkBoxId}" onclick="handleCheckBoxClick(this)"></input>`;
}
//function to handle checkbox click you would probably want to make it check if
//the checkbox is already checked if it is set value to unchecked
function handleCheckBoxClick(ev){
var checkBoxId = ev.id;
localStorage.setItem(checkBoxId, 'checked')
}

You can use :
Setting storage :
localStorage.setItem('checkbox', b.checked);
Getting storage :
var checkVal=localStorage.getItem('checkbox');

You'll have to do a bit of work. localStorage doesn't work in a snippet here, so a working example of the example code can be found # this JSFiddle
localStorage.setItem("Checkboxes", "{}");
const showCurrentCheckboxStates = () =>
document.querySelector("pre").textContent = `Checkboxes saved state ${
JSON.stringify(JSON.parse(localStorage.getItem("Checkboxes")), null, " ")}`;
const saveCheckboxState = (val, id) => {
localStorage.setItem("Checkboxes",
JSON.stringify({
...JSON.parse(localStorage.getItem("Checkboxes")),
[`Checkbox ${id}`]: val })
);
showCurrentCheckboxStates();
};
const createCheckbox = id => {
let cb = document.createElement('input');
cb.type = 'checkbox';
cb.dataset.index = id;
cb.title = `Checkbox ${id}`;
document.body.appendChild(cb);
// save the initial state
saveCheckboxState(0, id);
};
document.addEventListener("click", evt =>
evt.target.dataset.index &&
saveCheckboxState(+evt.target.checked, evt.target.dataset.index)
);
for (let i = 1; i < 11; i += 1) {
createCheckbox(i);
}

Related

Removing input from the DOM and local storage with vanilla JavaScript

I'm creating a ToDo app in vanilla JavaScript.
My goal is to be able to remove the input data from local storage when the corresponding "X" button has been clicked.
So far, when you click on an X button, the corresponding input field and checkbox are removed from the DOM with this function I created -
function removeToDoInput(button, input1, input2, input3) {
if (allToDoInputs.length > 2) {
button.addEventListener("click", () => {
toDoInputContainer.removeChild(input1);
toDoInputContainer.removeChild(input2);
toDoInputContainer.removeChild(input3);
for (let toDoInput = 0; toDoInput < allToDoInputs.length; toDoInput++) {
for (let i = 0; i < localStorage.length; i++) {
localStorage.removeItem("ToDo " + toDoInput);
console.log("test");
}
}
})
}
}
This works fine. But like I mentioned I also need to remove the corresponding input data from local storage.
Here is the 'add-to-do' button functionality. You'll notice the removeToDoInput is called which I don't think is good -
function createToDoInput() {
const newToDoInputCheckbox = document.createElement("INPUT");
newToDoInputCheckbox.setAttribute("type", "checkbox");
const newToDoInput = document.createElement("INPUT");
const newXBtn = document.createElement("SPAN");
toDoInputContainer.appendChild(newToDoInputCheckbox);
toDoInputContainer.appendChild(newToDoInput);
toDoInputContainer.appendChild(newXBtn);
newToDoInputCheckbox.classList.add("checkbox");
newToDoInput.classList.add("to-do-input");
newXBtn.classList.add("X");
newXBtn.innerHTML = "X";
newXBtn.addEventListener("click", removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn));
}
And here is the save button functionality -
function saveToDoInputs() {
localStorage.setItem("Title", toDoListTitle.value.trim());
for (let toDoInput = 0; toDoInput < allToDoInputs.length; toDoInput++) {
if (createToDoInput) {
localStorage.setItem("ToDo " + toDoInput, allToDoInputs[toDoInput].value.trim());
}
}
}
Both of these last functions I mentioned are attached to buttons through click event listeners.
How can I delete the input from local storage as well as the DOM?
This is incorrect and will be called immediately you assign the event handler
newXBtn.addEventListener("click", removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn));
you need
newXBtn.addEventListener("click", function() { removeToDoInput(newXBtn, newToDoInputCheckbox, newToDoInput, newXBtn)});
or similar
I have redesigned your code and now it
wraps the elements in their own container
delegates click and change to the list container
use relative addressing (closest)
gives the todo a unique ID and stores it in an object
retrieves the object from local storage when loading
adds the object to localStorage when changed
I also added a select all and delete selected
NOTE I have commented the localStorage interaction out because stacksnippets do not allow access to localStorage. Just uncomment them on your page
let todos = {};
// const saveTodos = localStorage.getItem("ToDo");
// if (saveTodos) todos = JSON.parse(saveTodos);
const toDoInputContainer = document.getElementById("toDoInputContainer");
const toggleSelDel = () => {
document.getElementById("seldel").classList.toggle("hide",Object.keys(todos).length===0); // show if there are actual entries - we can toggle on existense of checkboxes instead
}
const saveAndToggle = (id,why) => {
// localStorage.setItem("ToDo",JSON.stringify(todos));
console.log(id, why);
toggleSelDel()
};
const saveTodo = (id, text) => {
todos[id] = text;
saveAndToggle(id,"added")
};
const removeTodo = id => {
if (todos[id]) {
delete todos[id];
}
saveAndToggle(id,"deleted"); // toggle anyway
};
function createToDoInput() {
const todoContainer = document.createElement("div");
todoContainer.id = 'todo' + new Date().getTime(); // unique ID
const newToDoInputCheckbox = document.createElement("INPUT");
newToDoInputCheckbox.setAttribute("type", "checkbox");
const newToDoInput = document.createElement("INPUT");
const newXBtn = document.createElement("SPAN");
todoContainer.appendChild(newToDoInputCheckbox);
todoContainer.appendChild(newToDoInput);
todoContainer.appendChild(newXBtn);
newToDoInputCheckbox.classList.add("checkbox");
newToDoInput.classList.add("to-do-input");
newXBtn.classList.add("X");
newXBtn.innerHTML = "X";
toDoInputContainer.appendChild(todoContainer);
}
toDoInputContainer.addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.classList.contains("X")) {
const parent = tgt.closest("div")
removeTodo(parent.id);
parent.remove();
}
});
toDoInputContainer.addEventListener("change", function(e) {
const tgt = e.target;
if (tgt.classList.contains("to-do-input")) {
const id = tgt.closest("div").id;
if (tgt.value === "") removeTodo(id);
else saveTodo(id, tgt.value);
}
});
document.getElementById("add").addEventListener("click", createToDoInput);
toggleSelDel(); // possibly show the select all button
document.getElementById("selAll").addEventListener("click", function() {
const checked = this.checked;
[...toDoInputContainer.querySelectorAll("[type=checkbox]")].forEach(chk => chk.checked = checked)
});
document.getElementById("delAll").addEventListener("click", function() {
[...toDoInputContainer.querySelectorAll("[type=checkbox]:checked")].forEach(chk => {
const parent = chk.closest("div");
removeTodo(parent.id);
parent.remove();
});
});
.hide { display: none; }
<button id="add">Add</button>
<div id="seldel" class="hide"><label>Select all<input type="checkbox" id="selAll"/></label><button type="button" id="delAll">Delete selected</button></div>
<div id="toDoInputContainer"></div>

Local Storage issue

I'm trying to use local storage so that my invites stay on the page when refreshed. How would I go about implementing this into my code. I really don't know where to start and I'm really struggling with it. Please cans someone just show me how to implement this into my code. Ive been creating child elements and appending them to the UL in the HTML.
const form = document.getElementById("registrar");
const input = form.querySelector("input");
const mainDiv = document.querySelector(".main");
const ul = document.getElementById("invitedList");
const div = document.createElement('div');
const filterLabel = document.createElement('label');
const filterCheckBox = document.createElement('input');
filterLabel.textContent = "Hide those who havent responded";
filterCheckBox.type = 'checkbox';
div.appendChild(filterLabel);
div.appendChild(filterCheckBox);
mainDiv.insertBefore(div, ul);
/*
This creates a checkbox to see you has confirmed if they are coming
to the event or not.
*/
filterCheckBox.addEventListener("change", (e) => {
const isChecked = e.target.checked;
const lis = ul.children;
if (isChecked) {
for (let i = 0; i < lis.length; i += 1) {
let li = lis[i]
if (li.className === 'responded') {
li.style.display = '';
} else {
li.style.display = 'none';
}
}
} else {
for (let i = 0; i < lis.length; i += 1) {
let li = lis[i]
li.style.display = '';
}
}
});
/*
This function creates new list items (the invites).
*/
createLi = (text) => {
createElement = (elementName, property, value) => {
const element = document.createElement(elementName);
element[property] = value;
return element;
}
appendElement = (elementName, property, value) => {
const element = createElement(elementName, property, value);
li.appendChild(element);
return element;
}
const li = document.createElement("li");
appendElement("span", "textContent", text);
appendElement("label", "textContent", "Confirmed")
.appendChild(createElement("input", "type", "checkbox"));
appendElement("button", "textContent", "edit");
appendElement("button", "textContent", "remove");
return li;
}
}
form.addEventListener("submit", (event) => {
event.preventDefault();
const text = input.value;
input.value = "";
const li = createLi(text);
ul.appendChild(li);
});
ul.addEventListener("change", () => {
const checkbox = event.target;
const checked = checkbox.checked;
const listItem = checkbox.parentNode.parentNode;
if (checked) {
listItem.className = "responded";
} else {
listItem.className = "";
}
});
ul.addEventListener("click", (e) => {
if (e.target.tagName === 'BUTTON') {
const button = e.target;
const li = button.parentNode;
const ul = li.parentNode;
const action = button.textContent;
const nameActions = {
remove: () => {
ul.removeChild(li);
},
edit: () => {
const span = li.firstElementChild;
const input = document.createElement('input');
input.type = 'text';
input.value = span.textContent;
li.insertBefore(input, span);
li.removeChild(span);
button.textContent = 'Save';
},
Save: () => {
const input = li.firstElementChild;
const span = document.createElement('span');
span.textContent = input.value;
li.insertBefore(span, input);
li.removeChild(input);
button.textContent = 'edit';
}
};
nameActions[action]();
}
});
I only can give you an idea for this, if you are planning to save any big data to localStorage, you can save your data to string and remake it to JSON object!
Here's an exmaple for saving data set
var toSave = [ ];
var whatToSave = (Your invites data List, maybe a "text" var for your code?, organize
to array or loop for your "UL" tag)
for(var i=0;i<whatToSave.length;i++){
var obj = [];
obj[i] = {
text:whatToSave[i].text,
data1:whatToSave[i].data1,
data2:whatToSave[i].data2,
...
}
toSave.push(obj[i]);
}
var saveToString = JSON.stringify(toSave);
localStorage.setItem('invites', saveToString); //your invite data saved in local
storage
....
//after refreshing or when you need to use your saved data
var cameBack = JSON.parse(localStorage.getItem('invites'));
//this will return same data again
//and make function to make UL using retured data array
you don't really need to for loop and push if you already organized needed data to array, just wrote it to make you understand an idea to save data in localStorage. I don't know if this will help you but get an idea and implement it to your project :)

Persist checkbox state in plain JS after prompt

I have a simple TODO app written in vanilla javascript. Here is the application:
Issue/Problem that I am having at this point is:
When I click New todo button the existing checked state of the checkbox disappears.
I am not sure how to persist the checkbox state after prompt window OK click. Please find the source code below.
const classNames = {
TODO_ITEM: 'todo-container',
TODO_CHECKBOX: 'todo-checkbox',
TODO_TEXT: 'todo-text',
TODO_DELETE: 'todo-delete',
}
const checkbox = document.createElement( "input" );
checkbox.type = "checkbox"
checkbox.id = classNames.TODO_CHECKBOX
const list = document.getElementById('todo-list')
const itemCountSpan = document.getElementById('item-count')
const uncheckedCountSpan = document.getElementById('unchecked-count')
function newTodo() {
let newTodo = prompt("Please enter a todo item");
if(newTodo){
itemCountSpan.innerHTML = parseInt(itemCountSpan.innerHTML) + 1
list.append(checkbox)
list.innerHTML += "<li>" + newTodo
}
let allCheckBoxes = document.querySelectorAll("input[id='todo-checkbox']");
uncheckedCountSpan.innerHTML = allCheckBoxes.length
console.log(allCheckBoxes.length)
for(let i = 0; i < allCheckBoxes.length; i++){
allCheckBoxes[i].onclick = function() {
if ( this.checked ) {
uncheckedCountSpan.innerHTML = parseInt(uncheckedCountSpan.innerHTML) - 1
}
else {
uncheckedCountSpan.innerHTML = parseInt(uncheckedCountSpan.innerHTML) + 1
}
};
}
}
Please let me know if you have any thoughts/directions.
Thanks in advance.
You have two issues: first, you're appending the same checkbox every time. Second, you are directly editing innerHTML, which is forcing the DOM to re-render everything, reverting the state of the inputs. Here's how I would do it:
const classNames = {
TODO_ITEM: 'todo-container',
TODO_CHECKBOX: 'todo-checkbox',
TODO_TEXT: 'todo-text',
TODO_DELETE: 'todo-delete',
}
const list = document.getElementById('todo-list')
const itemCountSpan = document.getElementById('item-count')
const uncheckedCountSpan = document.getElementById('unchecked-count')
function newTodo() {
let newTodo = prompt("Please enter a todo item");
if(!newTodo){
return
}
itemCountSpan.innerHTML = parseInt(itemCountSpan.innerHTML) + 1
uncheckedCountSpan.innerHTML = parseInt(uncheckedCountSpan.innerHTML) + 1
const checkbox = document.createElement( "input" );
checkbox.onclick = function() {
if ( this.checked ) {
uncheckedCountSpan.innerHTML = parseInt(uncheckedCountSpan.innerHTML) - 1
}
else {
uncheckedCountSpan.innerHTML = parseInt(uncheckedCountSpan.innerHTML) + 1
}
};
checkbox.type = "checkbox"
checkbox.class = classNames.TODO_CHECKBOX
list.append(checkbox)
const listItem = document.createElement("li")
listItem.innerHTML = newTodo
list.append(listItem)
}
Note that I also replaced the id of the checkbox with a class - there are multiple checkboxes, and ids should be unique.

Javascript - Pass param function to async onchange event

Good evening,
I have a problem with the construction of form in Javascript. For avoid the repetition of code I'd like to use the same function:
function addCheckBoxItem(p, name, value) {
// add checkbox
var newCheckbox = document.createElement("input");
newCheckbox.type = "checkbox";
newCheckbox.setAttribute("value", p);
newCheckbox.setAttribute("id", p);
newCheckbox.setAttribute("name", name);
newCheckbox.onchange = function(){
var cbs = document.getElementsByName(name);
for (var i = 0; i < cbs.length; i++) {
cbs[i].checked = false;
}
this.checked = true;
// define the peer selected as choice
value = this.value;
// TODO: MY PROBLEM IS HERE
};
form.appendChild(newCheckbox);
// add label to checkbox
var label = document.createElement('label');
label.setAttribute("name", name);
label.htmlFor = p;
label.appendChild(document.createTextNode(p));
form.appendChild(label);
// add br tag to checkbox
var br = document.createElement("br")
br.setAttribute("name", name);
form.appendChild(br);
}
I call my function inside loop
for (i = 0; i < array.length; i++) {
addCheckBoxItem(array[i].key, nameItemCheckbox, peer_choice);
}
I know that value = this.value isn't possible because onchange event is Async but i want retrieve the value of this event and associate it with my param. I have find different response to this problem. One of this is: Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference I have understand the basic concept but none of the example is relevant to my problem. Someone could help me?
EDIT - SOLUTION
Thanks to #Tibrogargan i have modified my function in this way:
for (i = 0; i < array.length; i++) {
addCheckBoxItem(form, array[i].key, form_peer_available_class, peer_choice, (value) => peer_choice = value);
}
and
function addCheckBoxItem(p, name, value, callback) {
// add checkbox
var newCheckbox = document.createElement("input");
newCheckbox.type = "checkbox";
newCheckbox.setAttribute("value", p);
newCheckbox.setAttribute("id", p);
newCheckbox.setAttribute("name", name);
newCheckbox.onchange = function(){
var cbs = document.getElementsByName(name);
for (var i = 0; i < cbs.length; i++) {
cbs[i].checked = false;
}
this.checked = true;
// define the peer selected as choice
callback(this.value);
};
form.appendChild(newCheckbox);
// add label to checkbox
var label = document.createElement('label');
label.setAttribute("name", name);
label.htmlFor = p;
label.appendChild(document.createTextNode(p));
form.appendChild(label);
// add br tag to checkbox
var br = document.createElement("br")
br.setAttribute("name", name);
form.appendChild(br);
}
Pass callback into addCheckBoxItem like that
// accumulator
var data = {}
// callback
var storeData = (name, value, p) => data[name] = value;
// callback as third argument
addCheckBoxItem('data1', 'checkbox1', storeData);
addCheckBoxItem('data2', 'checkbox2', storeData);
addCheckBoxItem('data3', 'checkbox3', storeData);
Check full example here http://jsfiddle.net/gtqnc109/9/

How to change a button from another function?

var ButtonFarmAtivada = new Array();
function X() {
var tableCol = dom.cn("td"); //cell 0
//create start checkbox button
ButtonFarmAtivada[index] = createInputButton("checkbox", index);
ButtonFarmAtivada[index].name = "buttonFarmAtivada_"+index;
ButtonFarmAtivada[index].checked = GM_getValue("farmAtivada_"+index, true);
FM_log(3,"checkboxFarm "+(index)+" = "+GM_getValue("farmAtivada_"+index));
ButtonFarmAtivada[index].addEventListener("click", function() {
rp_farmAtivada(index);
}, false);
tableCol.appendChild(ButtonFarmAtivada[i]);
tableRow.appendChild(tableCol); // add the cell
}
1) is it possible to create the button inside an array as I'm trying to do in that example? like an array of buttons?
2) I ask that because I will have to change this button later from another function, and I'm trying to do that like this (not working):
function rp_marcadesmarcaFarm(valor) {
var vListID = getAllVillageId().toString();
FM_log(4,"MarcaDesmarcaFarm + vListID="+vListID);
var attackList = vListID.split(",");
for (i = 0; i <= attackList.length; i++) {
FM_log(3, "Marca/desmarca = "+i+" "+buttonFarmAtivada[i].Checked);
ButtonFarmAtivada[i].Checked = valor;
};
};
For number 1) yes, you can.
function createInputButton(type, index) { // um, why the 'index' param?
// also, why is this function called 'createInputButton'
// if sometimes it returns a checkbox as opposed to a button?
var inputButton = document.createElement("input");
inputButton.type = type; // alternately you could use setAttribute like so:
// inputButton.setAttribute("type", type);
// it would be more XHTML-ish, ♪ if that's what you're into ♫
return inputButton;
}
I don't really understand part 2, sorry.

Categories