I have this question in reference to
jQuery convert checkbox selections to array.
This works fine. I have modified it to match my requirements. My javascript is like below .
when a checkbox is checked I want to be added to the corresponding ID(which works fine) but when it is unchecked I want it to be removed..so I used pop. That works but it removed the last item ID rater than the unchecked item ID
` var arrayPgggoData = pgggoThisElem.parents('.elementor-widget-container').find('.pgggo-sort-container').attr('data-ajax-container');
var arrayPgggoData = JSON.parse(arrayPgggoData);
if ($(this).is(':checked')) {
const [_, taxonomy, __, attr] = $(this).attr('name').split('-');
arrayPgggoData[taxonomy] = arrayPgggoData[taxonomy] || [];
arrayPgggoData[taxonomy].push(attr.split('[')[0]);
} else {
const [_, taxonomy, __, attr] = $(this).attr('name').split('-');
arrayPgggoData[taxonomy] = arrayPgggoData[taxonomy] || [];
arrayPgggoData[taxonomy].pop(attr.split('[')[0]);
}`
Can someone help me out? :|
The pop function does as it is supposed which is basically removing the last element you have.
What you need here is splice(start, positions) but in this case you'd need to find the position in which the element appears. For this you would need to use indexOf(element).
You'd need something like this:
var index = indexOf(element);
arrayPgggoData.splice(index, 1);
You can check this article for more information on different ways to remove elements from arrays in JavaScript.
Related
Is it possible to change the index of the last item of a multidimensional input when my new item is created ?
Let me explain.
I have a button that is clone an item from my list, into my list. Each item contains several properties (date, category...)
This is an example of what I have when I display my form :
validation_form[classe][0][matieres][11][ressources][XXXXX][hasBeenRenewed]
What I do is that I clone all my item, but for now, the index XXXX is not updated.
How can I update the XXXX directly when I clone my item ? I thought I could count the number of items, and then change the index, but this would be painful and time consuming...
Use a regex in match() to create array of them then update the one you want and join() back together
const el = document.querySelector('input');
const prefix = el.name.split('[')[0],
ind = el.name.match(/\[(.*?)\]/g);
ind[5]= `[AAA]`;
el.name = `${prefix}${ind.join('')}`
console.log(el)
<input name='validation_form[classe][0][matieres][11][ressources][XXXXX][hasBeenRenewed]'/>
With a little bit of change, the #charlietfl answer works (had to change to fit into my case)
let inputs = new_ressource_clone.find('input');
let new_index = parseInt(count_ressource) + 1;
inputs.each(function() {
let input = $(this)
const prefix = input.attr('name').split('[')[0],
ind = input.attr('name').match(/\[(.*?)\]/g);
ind[5]= '['+new_index+']';
matiere_zone.attr('data-matiere-count-ressources', new_index);
let new_name = `${prefix}${ind.join('')}`;
input.attr('name', new_name);
})
new_ressource_clone.appendTo(liste_zone);
On my page with payment I need two inputs with total payment value:
- one that the client can see
- another one which is hidden.
I wrote a code which pass price of every element to the input when a client check a box with a product they want to pay for, but it works only with the one input.
I was trying to use different options (like getElementsByName and getElementsByClassName) but I am learning JS now and I have no idea how to solve this problem. :(
function select(selector, parent){
return Array.from((parent||document).querySelectorAll(selector));
}
var inputs = select('.sum'),
**totalElement = document.getElementById('payment-total');**
function sumUpdate(){
totalElement.value = inputs.reduce(function(result, input){
return result + (input.checked ? parseFloat(input.value) : 0);
}, 0).toFixed(0);
}
WHAT I TRIED:
var inputs = select('.sum'),
**totalElement = document.getElementsByName('payment-total')[0][1];**
var inputs = select('.sum'),
**totalElement = document.getElementsByName('payment-total, payment-total2')[0][1];**
var inputs = select('.sum'),
**totalElement = document.getElementsByName('payment-total).getElementsByName('payment-totalTwo);**
If I'm understanding you right, you want to put the computed value in both the id="payment-total" element and the id="payment-total2" element.
If so, just do what you've already done for payment-total, but for payment-total2 as well, see *** comments:
var inputs = select('.sum'),
totalElement = document.getElementById('payment-total'),
totalElement2 = document.getElementById('payment-total2'); // ***
function sumUpdate(){
//vvvvvvvvvvvvvvvvvvvvvv---- ***
totalElement2.value = totalElement.value = inputs.reduce(function(result, input){
return result + (input.checked ? parseFloat(input.value) : 0);
}, 0).toFixed(0);
}
I don't immediately see the reason for having both a visible and a hidden input, but if you need that for some reason, that's how you'd do it.
If it got to the point there were three or more elements you wanted to update, I'd probably give them all a class and select them the way you've selected your .sum elements, then compute the total once and assign it to all of them in a loop. But for just two, repeating the lookup and assignment seems fine.
I have a little problem with this javascript code, when I add more site on the list, the page doesn't load. I have to add more than 200 site.
I'm a noob with javascript. Can someone explain what is the problem, what
I'm doing wrong?
<script language="JavaScript" type="text/javascript">
var a = new Array(
'notiziepericolose.blogspot.it',
'ilcorrieredellanotte.it',
'ilmattoquotidiano.it',
'ilfattonequotidiano.com',
'rebubblica.altervista.org',
'coriere.net'
);
var aa = a.slice();
aa.sort();
document.write("<ol>");
document.write("<b>");
for (i = 0; i < a.length; i=i+1) {
document.write('<li id="demo'+i+'">'+a[i]+'</li>');
}
document.write("</b>");
document.write("</ol>");
</script>
I guess the first thing is that document.write is very rarely used now as there a better and more efficient ways of adding things (elements, text etc) to the DOM (more on that later). In addition, in your case, what you don't realise is that document.write is not like echo or println; each time it is used it clears the document, which is probably why you're not seeing anything appear. In other words, The results of multiple document.writes are not cumulative.
The second thing is that there are better ways of "labelling" elements than with ids, particularly if there are a lot of them on the page like you'll have. Again, there are now much better ways of targetting elements, or catching events than there were ten or fifteen years ago.
So, let's talk about your code.
You can quickly create a array using the [] brackets.
var arr = [
'notiziepericolose.blogspot.it',
'ilcorrieredellanotte.it',
'ilmattoquotidiano.it',
'ilfattonequotidiano.com',
'rebubblica.altervista.org',
'coriere.net'
];
You don't have to create a copy of the array in order to sort it - it can be done in place:
arr.sort();
I'm going to keep your loop but show you a different way of concatenating strings together. Some people prefer adding strings together, but I prefer this way, and that's to create an array of the little parts of your string and then join() them together**.
// Set l as the length, and create an output array called list
for (var i = 0, l = arr.length, list = []; i < l; i++) {
// I've changed things here. I've added a class called item
// but also changed the element id to a data-id instead
var li = ['<li class="item" data-id="', i, '">', arr[i], '</li>'];
// Push the joined li array of strings into list
list.push(li.join(''));
}
Assuming you have an element on your page called "main":
HTML
<div id="main"></div>
JS
You can add the list array as an HTML string to main by using [insertAdjacentHTML] method:
var main = document.getElementById('main');
// Note that I've given the ordered list an id called list
var HTML = ['<ol id="list"><b>', list.join(''), '</b></ol>'].join('');
main.insertAdjacentHTML('beforeend', html);
OK, so that's pretty easy. But I bet you're asking how you can target the individual items in the list so that if I click on one of them it alerts what it is (or something).
Instead of adding an event listener to each list item (which we could but it can work out performatively expensive the more items you have), we're going to attach one to the ol element we added that list id to and catch events from the items as they bubble up:
var ol = document.getElementById('list');
Then an event listener is added to the list that tells us what function (checkItem) is called when a click event is raised:
ol.addEventListener('click', checkItem);
Our function uses the event (e) to find out what the event's target was (what item was clicked), and alerts its text content.
function checkItem(e) {
alert(e.target.textContent);
}
You can see all this working in this demo. Hope some of this was of some help.
** Here's another way of sorting, and looping through the array using reduce:
var list = arr.sort().reduce(function (p, c, i) {
return p.concat(['<li class="item" data-id="', i, '">', c, '</li>']);
}, []).join('');
DEMO
if ES6 is possible for you, you can do it like this:
var a = new Array(
'notiziepericolose.blogspot.it',
'ilcorrieredellanotte.it',
'ilmattoquotidiano.it',
'ilfattonequotidiano.com',
'rebubblica.altervista.org',
'coriere.net');
var aa = a.slice();
var mL = document.getElementById('mylist');
aa.sort().map(el => {
var li = document.createElement("li");
var b = document.createElement("b");
var t = document.createTextNode(el);
b.appendChild(t);
li.appendChild(b);
mL.appendChild(li);
});
<ol id="mylist"></ol>
If you're using an Array, you can use a forEach instead of a loop.
var domUpdate = '';
var websites = ['notiziepericolose.blogspot.it','ilcorrieredellanotte.it','ilmattoquotidiano.it','ilfattonequotidiano.com','rebubblica.altervista.org','coriere.net'];
websites.forEach(function(website, index){
domUpdate += '<li id="website-' + ( index + 1 ) + '"><b>' + website + '</b></li>';
});
document.getElementById('hook').innerHTML = '<ol>' + domUpdate + '</ol>';
<div id="hook"></div>
I'm thinking document.write is the wrong choice here, as it seems to be clearing the document. https://developer.mozilla.org/en-US/docs/Web/API/Document/write Probably you want to bind the new content to existing html through document.getElementById or something like that
I have a number of checkboxes that are generated from a JavaScript API call from a database. I need to be able to pass the values of the checkboxes which are then selected by the user, and sent to the processing page. The issue is that the checkboxes don't have ID's associated with them(or this wouldn't be a problem) They all have the same name, but no ID's.
What is the best way to find which check boxes are selected, and pass their values to the following page?
One way I started was with an array:
var options = ["option1","option2","option3"];
var option 1 = [0];
var option 2 = [1];
var option 3 = [2];
On the processing page, using:
var option1 = getFromRequest('option1') || '';
var option2 = getFromRequest('option2') || '';
var option3 = getFromRequest('option3') || '';
Is there a better way of doing this?
I've changed the implementation to the following:
var values = []
$("input:checkbox.subIndustry").each(function(){
values.push(this.value);
});
passing the values to the success page with
window.location.href = REGISTER_SUCCESS +'&values='values.join(",")
which should then get the value with
var variablname = getFromRequest('values') || "";
This is returning Undefined. Any help?
An easy way to select them would be something like $("input[type=checkbox]:checked")
However, if you wanted to keep up with them as they are checked, even if they are added after you load, you could create a variable, then asign a delegation to the "change" state of each input that is a checkbox and update this variable on each change.
It's as simple as:
var checked, checkedValues = new Array();
$(function() {
$(document).on("change", "input[type=checkbox]", function(e) {
checked = $("input[type=checkbox]:checked");
// if you wanted to get an array of values of the checked elements
checkedValues = checked.map(function(i) { return $(this).val() }).get();
// make a string of the values as simple as joining an array!
var str = checkedValues.join(); // would return something like: value1,value2,ext...
});
})
Working Example
Since all your checkboxes have the same name, you can retrieve the checked ones using a variation of:
var checked = $('input[name=ckboxname]:checked');
see: :checked selector for more information
you can simply get the values of checked checkboxes by using
$('input[name=checkboxname]:checked').val();
this will give you the value of checkbox which is checked and for all values simply use
each function of jquery.
Turns out, the answer was to utilize indexOf in the underscore.js library. The solution had to be applied in the API being used to send data.
(_.indexOf(values, '9') != -1 ? 1 : '0'),
I have a series of editable lists which, on a press of a button should be transformed into some sort of data structure. When it has been turned into some sort of data I need to add duplicates together.
Example:
200g banana
100g apple
200g apple
Should be turned into a data list of some sort and should in the end look like this:
200g banana
300g apple
Here's my attempt:
//button click event
$(".calculate").bind("click", function(e)
{
//get the correct parent of the button
var parent = $(this).closest("#calc");
//get relevant data
parent.find(".options").each(function(index, element)
{
var opt1 = $(this).children(".opt1").children("input").val(); //weight
var opt2 = $(this).children(".opt2").children("input").val(); //ingredient
});
});
Basically I click the button and the above script finds all the relevant data.
How can I turn this into a multidimensional array or a list of objects I can search for duplicates in?
When I try to make a dynamic object it seems to fail and when I make a multidimensional array to search in I get blocked by inArray's inability to search through them.
Problem recap:
I am able to get the user data no problem. Turning it into a list and adding together duplicates is the problem.
I will suggest you to have a global object that will contain the summary, this will look like this:
$(".calculate").bind("click", function(e)
{
var fruits = {};
//get the correct parent of the button
var parent = $(this).closest("#calc");
//get relevant data
parent.find(".options").each(function(index, element)
{
var opt1 = $(this).children(".opt1").children("input").val(); //weight
var opt2 = $(this).children(".opt2").children("input").val(); //ingredient
// here is my code
if(fruits[opt2] == undefined) {
fruits[opt2] = opt1;
} else {
// assuming that opt1 is an integer
fruits[opt2] += opt1;
}
});
// use fruits variable here
});
Here's another variant, which also does some simple parsing in case you have 100g as input, versus 100. Also, the data structure gets reinitialized every time, so everything does not get doubled on every click.
$(".calculate").bind("click", function(e)
{
//get the correct parent of the button
var parent = $(this).closest("#calc");
var ingredients = {};
var extractWeight = function (input) {
// you can add other logic here
// to parse stuff like "1kg" or "3mg"
// this assumes that everything is
// in grams and returns just the numeric
// value
return parseInt(input.substring(0, input.length - 1));
}
//get relevant data
parent.find(".options").each(function(index, element)
{
var opt1 = $(this).children(".opt1").children("input").val(); //weight
var opt2 = $(this).children(".opt2").children("input").val(); //ingredient
// initialize to 0 if not already initialized
ingredients[opt2] = ingredients[opt2] ? ingredients[opt2] : 0;
ingredients[opt2] += extractWeight(opt1);
});
});
Here are some tips:
{} is called an object literal and is used to create a new empty object
object members can be accessed dynamically through the [] notation (i.e. if x === "name" then o[x] === o.name)
variables are visible inside functions that are at the same level or deeper in the scope - like in my example I use ingredients in the each function.
arrays in JavaScript only support numeric keys, so you won't have stuff like PHP's "associative arrays". Objects fill this gap in JS.
Here is a jsFiddle that does what you're looking for :) http://jsfiddle.net/LD9TY/
It has two inputs, one for the item name and the other for the amount. When you click add, it checks an object to see if the item was already added. If so, it increments the amount for that item based on your input. If not, it adds that item with the amount you specified. It then goes and builds a ul with all the items in your "store".
Note that this is a quick and dirty example, so there is no type checking or validation going on :)