I have a dynamically generated form with groups of checkboxes representing categories of companies. These eventually get plotted on a dynamic chart (not shown here). Each group of companies has a toggle button to turn all the checkboxes on or off in each category.
I have a jQuery handler for the first toggle button (Tech Giants) using its ID and then checks or unchecks all the boxes in that group accordingly.
My question is this, which refers to the last portion of code in the block below. Instead of manually coding a handler for each toggle button, how can I create one that will apply to all of them on the page? Each button should only check or uncheck all the boxes in its specific category. Note that the first button on the page is separate, and not part of the category selection checkboxes we want to handle.
Here's the code in JSFiddle:
https://jsfiddle.net/gq5tw309/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- This button is different than the other buttons -->
<button class="button-text" id="customize-button">Open User Settings</button>
<!-- Placeholder for dynamic form -->
<div id="company-selection-form"></div>
<script type="text/javascript">
function toMachineString(humanString) {
var machineString = humanString.replace(/\s+/g, '-').toLowerCase();
machineString = machineString.replace('&','');
return machineString;
}
// Setup the form
var categories = new Map([
['Tech Giants',['Alphabet','Amazon','Apple','Facebook','Microsoft']],
['Semiconductors', ['AMD','Intel','Nvidia']],
['Telecoms',['AT&T','Verizon','Sprint','T-Mobile']]
// ...
]);
// Build company selection form inputs
let companySelectionHTML = '';
for (let category of categories) {
categoryName = category[0];
categoryList = category[1];
// Setup a div to differentiate each category of companies.
// Will be used for turning on/off categories en masse
companySelectionHTML += `<div id="${toMachineString(categoryName)}">\n`;
// Category heading
companySelectionHTML += `<h4>${categoryName}</h4><button id="btn-${toMachineString(categoryName)}" data-checked="true">Toggle</button>`;
categoryList.forEach(companyName => {
companySelectionHTML += `
<label class="checkbox-label">
<input id="x-${toMachineString(companyName)}" class="checkbox" type="checkbox" name="company" value="${companyName}" checked>
<label for="x-${toMachineString(companyName)}">${companyName}</label>
</label>`;
});
companySelectionHTML += '</div>\n</div>\n</div>\n';
}
// Append to DOM
const companySelectionId = document.getElementById('company-selection-form');
companySelectionId.insertAdjacentHTML('beforeend', companySelectionHTML);
// Arm the toggle button
// HOW DO I APPLY THIS TO ALL THE TOGGLE BUTTONS INSTEAD OF JUST ONE?
$(document).ready(function(){
$('#tech-giants').click(function() {
// Access the data object of the button
var buttonData = $(this).data();
// Set all checkboxes 'checked' property
$('#tech-giants input[type=checkbox]').prop('checked', !buttonData.checked);
// Set the new 'checked' opposite value to the button's data object
buttonData.checked = !buttonData.checked;
// Update the chart -- code goes here
// dynamically-refresh-chart();
});
});
</script>
Thank you!
First bind your event like so for dynamically generated HTML (the buttons):
$('body').on("click", ".yourClass", function () {
//Your code goes here
});
Then use the class on the button instead of an ID, to apply the event listener to all buttons with the given class.
You could do it like this: bind the click() event to all buttons that have an id starting with "btn" $(document).on("click", "button[id^='btn']", function() {}); or just add a class to all toggle buttons and bind the click() event to them, which I did in the following code.
function toMachineString(humanString) {
var machineString = humanString.replace(/\s+/g, '-').toLowerCase();
machineString = machineString.replace('&', '');
return machineString;
}
// Setup the form
var categories = new Map([
['Tech Giants', ['Alphabet', 'Amazon', 'Apple', 'Facebook', 'Microsoft']],
['Semiconductors', ['AMD', 'Intel', 'Nvidia']],
['Telecoms', ['AT&T', 'Verizon', 'Sprint', 'T-Mobile']]
// ...
]);
// Build company selection form inputs
let companySelectionHTML = '';
for (let category of categories) {
categoryName = category[0];
categoryList = category[1];
// Setup a div to differentiate each category of companies.
// Will be used for turning on/off categories en masse
companySelectionHTML += `<div id="${toMachineString(categoryName)}">\n`;
// Category heading
companySelectionHTML += `<h4>${categoryName}</h4><button id="btn-${toMachineString(categoryName)}" class="category" data-checked="true">Toggle</button>`;
categoryList.forEach(companyName => {
companySelectionHTML += `
<label class="checkbox-label">
<input id="x-${toMachineString(companyName)}" class="checkbox" type="checkbox" name="company" value="${companyName}" checked>
<label for="x-${toMachineString(companyName)}">${companyName}</label>
</label>`;
});
companySelectionHTML += '</div>\n</div>\n</div>\n';
}
// Append to DOM
const companySelectionId = document.getElementById('company-selection-form');
companySelectionId.insertAdjacentHTML('beforeend', companySelectionHTML);
$(document).ready(function() {
$(document).on("click", ".category", function() {
var buttonData = $(this).data();
$(this).closest("div").find('input[type=checkbox]').prop('checked', !buttonData.checked);
buttonData.checked = !buttonData.checked;
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="button-text" id="customize-button">Open User Settings</button>
<div id="company-selection-form"></div>
Related
Following is an example of a sample webform I made in Google Apps Script, where I'm trying to dynamically add three select dropdowns and an input element whenever the add button is clicked. The elements should render in following order -
dropdown dropdown input dropdown.
I'm using materialize framework for this.
After a lot of trying and going through the materializecss documentation, I was able to render the text input field as expected. But, the dropdowns still won't render. Clearly, I'm making some mistake, cannot figure out what and where.
I'm including the code files-
Code.gs
function doGet(e) {
Logger.log(e);
return HtmlService.createTemplateFromFile('form_materialize').evaluate();
}
function include(fileName){
return HtmlService.createHtmlOutputFromFile(fileName).getContent();
}
form_materialize.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<!-- google font pack link -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Mini materialize.css cdn link -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
<?!= include('css_scripts'); ?>
</head>
<body>
<div class="container">
<div class = "row">
<h1>A Sample Form</h1>
</div>
<div id="productsection">
<!-- product details like "Product Type"(dropdown), "Products"(dropdown), "Product Qty"(text input field), "Unit"(dropdown) to be added here dynamically -->
</div>
<div class = "row">
<a class="btn-floating btn-large waves-effect waves-light red" id="addproduct"><i class="material-icons">add</i></a>
</div>
</div>
<!-- Mini materialize.js cdn link -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<?!= include('js_scripts_materialize'); ?>
</body>
</html>
js_scripts_materialize.html
<script>
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, options);
});
let counter = 0;
const orderTypeList = ["PH", "ECOM"];
const optionList = ["Test Product 1", "Test Product 2", "Test Product 3", "Test Product 4", "Test Product 5"];
const unitOptionList = ["KGS", "PCS", "BAGS"];
document.getElementById("addproduct").addEventListener("click", addInputField);
function addInputField(){
counter++;
// everytime when "add product" button is clicked, the following elements must be added to the "<div id="produc></div>" tag.
// <div class="row">
// <div class="input-field col s4" id="divone">
// <select id="productX">
// <option>option-i</option>
// <option>option-1</option>
// <option>option-2</option>
// ...
// ...
// <option>option-n</option>
// <select>
// </select>
// <div class="input-field col s4" id="divtwo">
// <input id="productqtyX" type="text">
// <label for="productqtyX">Quantity</label>
// </div>
// <div class="input-field col s4" id="divthree">
// <select id="productUnitX">
// <option>option-1</option>
// <option>option-2</option>
// ...
// ...
// <option>option-n</option>
// </select>
// </div>
// </div>
// creates a new div of class row
const newDivElem = createElementTemplate('div', null, ['row']);
// creates a new select tag for order type dropdown
const newOrderTypeSelectElem = createElementTemplate('select', "ordertype" + counter.toString());
// generates the content of the dropdown for products and is inserted to the above "productX" select tag
createOptionsElem(newOrderTypeSelectElem, orderTypeList);
// creates a new select tag for product dropdown
const newProductSelectElem = createElementTemplate('select', "product" + counter.toString());
// generates the content of the dropdown for products and is inserted to the above "productX" select tag
createOptionsElem(newProductSelectElem, optionList);
// creates a input element for quantity input
const newQtyInputElem = createElementTemplate('input', 'productqty' + counter.toString(), ['validate']);
newQtyInputElem.type = 'text';
// creates a label for the quantity input element
const newQtyLabelElem = createElementTemplate('label');
newQtyLabelElem.textContent = "Quantity";
//Creates a new select element for product quantity unit(dropdown)
const newUnitSelectElem = createElementTemplate('select', 'productqtyunit' + counter.toString());
// generates the content of the dropdown for units and is inserted to the above "productqtyunitX" select tag
createOptionsElem(newUnitSelectElem, unitOptionList);
//create inner "div" tags with class "input-field col s4" as described in materializecss documentation
const innerDivElems = [];
for(let i = 0; i < 4; i++){
innerDivElems.push(createElementTemplate('div', `div${(Number(i) + 1)}`, ['input-field', 'col', 's3']));
}
innerDivElems[0].appendChild(newOrderTypeSelectElem);
innerDivElems[1].appendChild(newProductSelectElem);
innerDivElems[2].appendChild(newQtyInputElem);
innerDivElems[2].appendChild(newQtyLabelElem);
innerDivElems[3].appendChild(newUnitSelectElem);
//Inserts select, quantityInput, quanityLabel, newUnitSelectTag tags in div child
for(let i in innerDivElems){
newDivElem.appendChild(innerDivElems[i]);
}
// Finally, appends the newly created div tag to the productSection tag.
document.getElementById('productsection').appendChild(newDivElem);
}
function createOptionsElem(selectElem, optionsArr){
const newDefaultOptionElem = document.createElement('option');
newDefaultOptionElem.disabled = true;
newDefaultOptionElem.setAttribute('selected', true);
newDefaultOptionElem.textContent="Choose your option";
selectElem.appendChild(newDefaultOptionElem);
for(let i in optionsArr){
const newOptionElem = document.createElement('option');
newOptionElem.textContent = optionsArr[i];
newOptionElem.value = optionsArr[i];
// Inserts the option tag in select tag
selectElem.appendChild(newOptionElem);
}
}
// function to create a new element
function createElementTemplate(tagType, idVal, classNameList){
const newElement = document.createElement(tagType);
if(idVal !== undefined)
newElement.id = idVal;
if(classNameList !== undefined){
for(let i in classNameList){
newElement.classList.add(classNameList[i]);
}
}
return newElement;
}
</script>
Although I'm not sure whether I could correctly understand your expected result, how about the following modification?
In this modification, your js_scripts_materialize.html is modified.
Modified script:
I think that in this case, this part might not be required to be used.
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems, options);
});
And also, please modify addInputField() as follows.
From:
document.getElementById('productsection').appendChild(newDivElem);
To:
document.getElementById('productsection').appendChild(newDivElem);
var elems = document.querySelectorAll('select'); // Added
M.FormSelect.init(elems); // Added
By this modification, I thought that when you click a red button, you can see the dropdown lists.
I have a low level knowledge of javascript and am trying to create a basic image based quiz that passes data back to a search page for local businesses.
Each image would have it's own "tag" as the image ID that relates to one of the options in the search. Ie. Outdoor, Ballroom, Barn, Garden, etc.
Upon submission, it would send the selected image ID's data to www.sitename/search/?_characteristics=TAG1,TAG2,TAG3
That search page will filter the business listings by the tags. Currently it's search function filters the businesses with the following format: website.com/search/?_characteristics=TAG1%2CTAG2
The HTML would look like this:
<img src="http://website.com/image1" id="TAG1"/>
<br/>
<img src="http://website.com/image2" id="TAG2"/>
<form action="https://website.com/business/?&_characteristics=TAG1, TAG2, TAG3" method="get">
<input type="submit" value="View Selected"/>
What you want is the following
Register a click handler on your images to
Capture ids into a collection (array or Set)
Toggle the "selected" class
Register a submit handler on the form to inject an hidden input element, transforming the tag collection into a CSV and setting it to the input value
const form = document.querySelector("form")
const tags = new Set()
document.querySelectorAll("img[id]").forEach(img => {
img.addEventListener("click", () => {
const selected = img.classList.toggle("selected")
tags[selected ? "add" : "delete"](img.id)
})
})
form.addEventListener("submit", (e) => {
const input = Object.assign(document.createElement("input"), {
name: "_characteristics",
type: "hidden",
value: ([...tags]).join(",")
})
form.append(input)
// this is just for the example, omit the following
e.preventDefault()
console.log(`Submitting to ${form.action}?${new URLSearchParams(new FormData(form))}`)
input.remove()
})
img { border: 2px solid grey; }
img.selected { border-color: red; }
<img src="https://picsum.photos/100" id="TAG1"/>
<br/>
<img src="https://picsum.photos/100" id="TAG2"/>
<form action="https://website.com/business/" method="get">
<input type="submit" value="View Selected"/>
</form>
I'm not sure how you want to get the selected img, but here's a way to do it:
Add the class active to the selected img
When clicking on the button, get the id and push it to the output array
Create the link of the tags (id's)
Read the comments below for the detailed explanation.
// Get the images and the submit button
let images = document.querySelectorAll('img');
let btn = document.getElementById('btn');
// Array to hold the tags
let output = [];
// variable to hold the link
let link = '';
// Add the class active to the selected images
for(let i = 0; i < images.length; i++) {
// For each image onclick:
images[i].addEventListener('click', () => {
// Toggle the `active` class on click
images[i].classList.toggle('active');
});
}
// Button onclick:
btn.addEventListener('click', () => {
for(let i = 0; i < images.length; i++) {
// Get the images with the `active` class and push the id to the output array
images[i].classList.contains('active') ? output.push(images[i].getAttribute('id')) : '';
}
// Remove duplicates if found
let uniq = [...new Set(output)];
// Create the link by adding the tags to the string (output values)
link = `www.sitename/search/?_characteristics=${uniq.join(',')}`;
// Print the link to the console
console.log(link);
});
img.active {
box-shadow: 0 0 1px 1px #121212;
}
5. <img src="http://www.gravatar.com/avatar/e1122386990776c6c39a08e9f5fe5648?s=128&d=identicon&r=PG" id="air-conditioned"/>
<br/>
6. <img src="http://www.gravatar.com/avatar/e1122386990776c6c39a08e9f5fe5648?s=128&d=identicon&r=PG" id="outdoor"/>
<br/>
7. <img src="http://www.gravatar.com/avatar/e1122386990776c6c39a08e9f5fe5648?s=128&d=identicon&r=PG" id="indoor"/>
<br/>
8. <img src="http://www.gravatar.com/avatar/e1122386990776c6c39a08e9f5fe5648?s=128&d=identicon&r=PG" id="house"/>
<br/>
<button id="btn">Submit</button>
I am trying to generate link on the button when multiple Checkbox is clicked based on the value. I have used the below link and it's working fine and I am able to generate link.
Create a dynamic link based on checkbox values
The issue is that when I select the checkbox for the first time it generates a link to /collections/all/blue+green but when I again select/deselect the different value its duplicates and ADDs the values with old Link → to collections/all/blue+green+blue+green
For Live Issue check on mobile View Click on filter on bottom => https://faaya-gifting.myshopify.com/collections/all
$("input[type=checkbox]").on("change", function() {
var arr = []
$(":checkbox").each(function() {
if ($(this).is(":checked")) {
arr.push($(this).val())
}
})
var vals = arr.join(",")
var str = "http://example.com/?subject=Products&checked=" + vals
console.log(str);
if (vals.length > 0) {
$('.link').html($('<a>', {
href: str,
text: str
}));
} else {
$('.link').html('');
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<input type="checkbox" name="selected" value="Blue" class="products"> Blue<br>
<input type="checkbox" name="selected" value="Green" class="products"> Green<br>
<input type="checkbox" name="selected" value="Purple" class="products"> Purple
<br>
<span class="link"></span>
For Live Issue check on mobile View Click on filter on bottom => https://faaya-gifting.myshopify.com/collections/all
I see what's going on now. What's causing the duplicate is actually multiple checkboxes having the checked value.
If you run this code in your console, you should see that you have twice of the item checked as its length:
// Run this in your browser console
$('input[type=checkbox]:checked').length
For example, if I have Wood and Metal checked and clicked Apply, running the code above gives length of 4 instead of just 2. Meaning, you have a duplicate checkbox input for each filter hidden somewhere in your code. I have verified this.
As options, you can:
Try to remove the duplicate checkbox input – Best Option; or
Add class to narrow down your selector to just one of the checkbox input containers.
Here's a screenshare of what's going on: https://www.loom.com/share/2f7880ec3435427a8378050c7bf6a6ea
UPDATED 2020/06/09:
If there's actually no way to modify how your filters are displayed, or add classes to narrow things down, we can opt for an ad hoc solution which is to actually, just remove the duplicates:
// get all your values
var arr = []
$(":checkbox").each(function() {
if ($(this).is(":checked")) {
arr.push($(this).val().toLowerCase())
}
})
// removes duplicates
var set = new Set(arr)
// convert to array and join
var vals = [...set].join(",")
I am bit bad in jquery. Am I doing right?
Should I just add the script which I have written below
$("input[type=checkbox]").on("change", function() {
var arr = []
$(":checkbox").each(function() {
if ($(this).is(":checked")) {
arr.push($(this).val().toLowerCase())
}
})
// removes duplicates
var set = new Set(arr)
// convert to array and join
var vals = [...set].join(",")
var str = "http://example.com/?subject=Products&checked=" + vals
console.log(str);
if (vals.length > 0) {
$('.link').html($('<a>', {
href: str,
text: str
}));
} else {
$('.link').html('');
}
})
Am I right?
Or should I add any values on var set = new Set(arr) or var vals = [...set]
Thank you for you help Algef
I have coded some simple function which allow me to add order. I have also dynamically created the button which when called will remove the current html element which is a table row. Now, I am stuck with finding the current element index which I needed so I can use splice to remove it from the array.
const order = [];
const customer = {
name: '',
totalCups: 0
}
$('#btnAdd').click(function() {
debugger
var itemName = $('#customerName');
var itemTotalCups = $('#customerTotalCups');
customer.name = itemName.val();
customer.totalCups = itemTotalCups.val();
// Data structure Queue
order.push(Object.assign({}, customer));
// UI - HTML rendering - start
if (order.length === 1) {
// Create table column name
$('#AllOrders').append('<table id="tbl" class="table table-bordered"><tr><td>Customer</td><td>Cups</td><td></td></tr></table>');
}
var itemElement = `<tr><td>${itemName.val()}</td><td>${itemTotalCups.val()}</td><td><a class='del' href='#'>Cancel order</a></td></tr>`;
$('#tbl').append(itemElement);
// UI - HTML rendering - end
$('.del').click(function(e) {
e.stopImmediatePropagation();
// Delete order object
debugger
//var elm = $(this).parent().text().substr(0, $(this).parent().text().length-1);
console.log(elm);
console.log(order.indexOf(elm));
//order.splice(order.indexOf(elm),1);
//order.splice(2,1);
// Delete HTML element
$(this).parent().parent().remove();
})
// Reset textbox
itemName.val("");
itemTotalCups.val("");
// Optional Design
$('#ViewAllOrders').click();
debugger;
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="customerName" type="text" />
<input id="customerTotalCups" type="number" />
<button id="btnAdd">Add</button>
<div id="AllOrders"></div>
I search for the solution but can't figure out the commented code below to find the element
//var elm = $(this).parent().text().substr(0, $(this).parent().text().length-1);
I am stuck inside $('.del').click event handler.
You can find the element in the order array by getting the index of the row where the clicked cancel button is.
To do so, you have to first get the current row. You can use the closest method:
var $row = $(this).closest('tr');
Now, you can get the index of the current row through the index method. You have to take into account that you have the tr for the header, you we need to substract one:
var index = $row.index() - 1;
Your final code should look like:
$('.del').click(function(e) {
e.stopImmediatePropagation();
var $row = $(this).closest('tr');
var index = $row.index() - 1;
order.splice(index, 1);
// Delete HTML element
$row.remove();
});
You can find the parent tr element and use that element to find the customer name and delete that node from DOM.
Couple of methods you want to try out:
.closest(): find the first match in the parent DOM hierarchy
https://api.jquery.com/closest
.filter(): filter an array based on some condition
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
So, basically you can find the closest tr node using closest and then find the customer name from within this tr's first td element.
Then, use filter on order to remove its instance from the order array.
Below is the changed code from the snippet:
$('.del').click(function(e) {
e.stopImmediatePropagation();
// Delete order object
var elm = $(this).closest('tr');
var nameToDelete = elm.find('td:first').text();
// filter out order
order = order.filter(item => item.name !== nameToDelete);
console.log('order now is = ', order);
// Delete HTML element
elm.remove();
});
More appropriately, learn about using HTML data-* Attributes along with id and class that could really ease up DOM manipulation. There are many samples online. Give that a try.
Cheers!
var order = [];
const customer = {
name: '',
totalCups: 0
};
$('#btnAdd').click(function() {
var itemName = $('#customerName');
var itemTotalCups = $('#customerTotalCups');
customer.name = itemName.val();
customer.totalCups = itemTotalCups.val();
// Data structure Queue
order.push(Object.assign({}, customer));
// UI - HTML rendering - start
if (order.length === 1) {
// Create table column name
$('#AllOrders').append('<table id="tbl" class="table table-bordered"><tr><td>Customer</td><td>Cups</td><td></td></tr></table>');
}
var itemElement = `<tr><td>${itemName.val()}</td><td>${itemTotalCups.val()}</td><td><a class='del' href='#'>Cancel order</a></td></tr>`;
$('#tbl').append(itemElement);
// UI - HTML rendering - end
$('.del').click(function(e) {
e.stopImmediatePropagation();
// Delete order object
var elm = $(this).closest('tr');
var nameToDelete = elm.find('td:first').text();
// filter out order
order = order.filter(item => item.name !== nameToDelete);
console.log('order now is = ', order);
// Delete HTML element
elm.remove();
});
// Reset textbox
itemName.val("");
itemTotalCups.val("");
// Optional Design
$('#ViewAllOrders').click();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="customerName" type="text" />
<input id="customerTotalCups" type="number" />
<button id="btnAdd">Add</button>
<div id="AllOrders"></div>
Here is the section which is confusing me:
<script type="text/javascript">
//declaring veriables
var inputField = document.getElementById("input");
var addBtn = document.getElementById("addBtn");
var html = "";
var x = 0;
addBtn.addEventListener('click', function(){
var text = inputField.value;
addToList(text);
})
//adds items to list
function addToList(text){
html += "<li id=(x+=1)><h4><input type='checkbox' id=(x+=1) onclick= 'clearspecifieditems()'>"+text+"</h4></li>";
document.getElementById("myList").innerHTML = html;
inputField.value = "";
}
//clears items
function clearspecifieditems(itemid)
{
//delete selected item
};
So the goal here is to create a to-do list (I'm new to coding). The addToList(text) function is supposed to create a new list item and assign a sequential ID to it. However, I cannot seem to figure out how to have it generate the ID. In addition, clearspecifieditems(itemid) is supposed to get the IDs of all the list items that are checked, and clear all of them.
For the first part of your question either use string concatenation similar to how you added the text variable...
function addToList(text) {
const id = x + 1;
html += '<li id="' + id + '"><h4><input type="checkbox" id="' + id + '">' + text + '</h4></li>';
// ..
}
...or use a template literal:
function addToList(text) {
const id = x + 1;
html += `<li id="${id}"><h4><input type="checkbox" id="${id}" />${text}</h4></li>`;
// ..
}
HOWEVER, for the second part, how to clear checked boxes:
I purposely left the onclick out of the above code because it sounds as if you need a separate button to clear the checkboxes:
// Grab the button and add an click listener to it
// to call `clearSpecifiedItems`
const button = document.querySelector('.clear');
button.addEventListener('click', clearSpecifiedItems, false);
function clearSpecifiedItems() {
// Select all the checked checkboxes using their class
const selected = document.querySelectorAll('.test:checked');
// Set their checked property to false (or null)
selected.forEach(input => input.checked = false);
}
<input class="test" type="checkbox" />
<input class="test" type="checkbox" />
<input class="test" type="checkbox" />
<input class="test" type="checkbox" />
<button class="clear">Clear</button>
Notice that none of these inputs have IDs. I've used a class to pick up the elements instead. So unless you're using the ids for anything else it makes the first part of your code redundant. Just use a CSS selector to grab the elements you need and then process them. No IDs required!
I can see what you're going for. You are almost there. Just a little bit of syntactical error, and a bit of a logical one.
You see, when you increment x two times, You will have a different id for the <li> and the <input>. What I suggest is you increment the x beforehand and then use it.
You can do it like this:
function addToList(text){
x++;
html += "<li id="+ x +"><h4><input type='checkbox' id="+ x +" onclick= 'clearspecifieditems()'>"+text+"</h4></li>";
document.getElementById("myList").innerHTML = html;
inputField.value = "";
}
or this (ES6)
function addToList(text){
x++;
html += `<li id=${x}><h4><input type='checkbox' id=${x} onclick= 'clearspecifieditems()'>${text}</h4></li>`;
document.getElementById("myList").innerHTML = html;
inputField.value = "";
}
Is it absolutely necessary that you must only increment? Can the ID's be truly unique? I suggest you use UUID in that case
Your second question is how to make clearspecifieditems work. Here's what you can do. You can pass the context, or simply the checkbox that was clicked and then get it's ID easily..
So you would define your function something like this:
function clearspecifieditems(element){
//delete selected item
console.log(element.id); // this would give you the ID of the selected checkbox and then you can do whatever with it
};
and slightly modify your function call on the click event
html += "<li id="+ x +"><h4><input type='checkbox' id="+ x +" onclick= 'clearspecifieditems(this)'>"+text+"</h4></li>";
Note this this part.
More more information, See this
Just use string interpolation to reference the x variable and increment it by one every time you add a new item as follows:
/* JavaScript */
var inputField = document.getElementById("input");
var addBtn = document.getElementById("addBtn");
var output = document.getElementById("output");
var html = "";
var x = 0;
function addToList(text) {
output.innerHTML += `<li id=id${x}><h4><input type='checkbox' id=${x}>This list item has an id: id${x}"</h4></li>`;
inputField.value = "";
x++;
}
addBtn.addEventListener('click', function(){
var text = inputField.value;
addToList(text);
})
<!-- HTML -->
<input type="text" id="input" />
<button id="addBtn">Add Items</button>
<div id="output"></div>
And for removing checked elements, simply add another button, say removeBtn and then add a click listener to the button that invokes the clearspecifieditems().
Inside the function, assign a variable to a list of all the checkboxes, loop through the variable using forEach and remove any checkbox that is not checked like this:
function clearspecifieditems() {
var check = document.querySelectorAll('[id^="id"]');
check.forEach(checkBox => {
if(checkBox.children[0].children[0].checked){
checkBox.remove();
}
});
}
removeBtn.addEventListener('click', clearspecifieditems);
#output {list-style: none;}
/* <input type="text" id="input" />
<button id="addBtn">Add Items</button> */
<ul id="output">
<li id="id0"><h4><input type="checkbox" id="input0">This list item has an id: id0"</h4></li>
<li id="id1"><h4><input type="checkbox" id="input1">This list item has an id: id1"</h4></li>
<li id="id2"><h4><input type="checkbox" id="input2">This list item has an id: id2"</h4></li>
<li id="id3"><h4><input type="checkbox" id="input3">This list item has an id: id3"</h4></li>
</ul>
<hr>
<button id="removeBtn">Remove</button>
You're sending X as 1. You should do like this :
var input = document.getElementById("input");
var div = document.getElementById("div");
var button = document.getElementById("addbutton");
var id = 0;
button.onclick = function() {
text = input.value;
addtask(text)
}
function addtask(text) {
var element = document.createElement("li");
element.setAttribute("id", id)
var deleteE = document.createElement("input");
deleteE.setAttribute("type", "checkbox");
deleteE.setAttribute("onclick", "deleteX(" + id + ")");
var node = document.createTextNode(text);
element.appendChild(deleteE);
element.appendChild(node);
div.appendChild(element);
id += 1;
}
function deleteX(id) {
document.getElementById(id).style.visibility = "hidden";
}
<input id="input"> <button id="addbutton"> add </button>
<div id="div"></br> </div>