Remove array element if it doesn't exist - javascript

I want to remove an element from the array ids if the element doesn't exist.
<div id="nl-form-0" >
<input type="text" id='dynamic_translation_0_0' value="15" />
<input type="text" id='dynamic_translation_0_1' value="15" />
<input type="text" id='dynamic_translation_0_2' value="15" />
<input type="text" id='dynamic_translation_1_2' value="15" />
</div>
ids = [
"transliterateTextarea",
"dynamic_translation_0_0",
"dynamic_translation_0_1",
"dynamic_translation_0_2",
"dynamic_translation_1_0",
"dynamic_translation_1_1",
"dynamic_translation_1_2"];
check_remove_ids_array(ids);
console.log(ids);
console.log($("#dynamic_translation_1_1").length);
function check_remove_ids_array(array_in) {
array_length = array_in.length;
for (n = 0; n <= array_length; n++) {
if ($("#" + array_in[n]).length == '0') {
removeValue(ids,array_in[n]);
}
}
}
function removeValue(arr, value) {
var array = arr;
for (var i = array.length-1; i--;) {
if (array[i] === value) {
array.splice(i, 1);
}
}
return array;
}
In the above code dynamic_translation_1_1 does not exist. I want to remove that or any other element from the array ids if the element doesn't exist

Why does/did it not work?
Basically you had a return and assigning problem. Since there are no reference parameters in JavaScript you have to assign the returned array back to the initial ids. Same goes for your removeValue() function.
Suggestion
Use the array.filter() prototype instead. It solves your problem more elegantly.
Example
<html>
<head>
<script src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js'></script>
<script>
$(document).ready(function(){
ids = ["transliterateTextarea", "dynamic_translation_0_0", "dynamic_translation_0_1", "dynamic_translation_0_2", "dynamic_translation_1_0", "dynamic_translation_1_1", "dynamic_translation_1_2"];
ids = check_remove_ids_array(ids); //We have to assign it back, else we always get the initial ids array!
console.log(ids);
console.log($("#dynamic_translation_1_1").length);
});
function check_remove_ids_array(array_in){
array_length = array_in.length; //Is not required in this example anymore.
//We use the filter function instead.
return array_in.filter(function(item){return $("#" + item).length > 0})
};
</script>
</head>
<body>
<input type = 'text' id = 'dynamic_translation_0_0' value = '15' />
<input type = 'text' id = 'dynamic_translation_0_1' value = '15' />
<input type = 'text' id = 'dynamic_translation_0_2' value = '15' />
<input type = 'text' id = 'dynamic_translation_1_2' value = '15' />
</body>
</html>

Related

Grabbing form data into an object with jQuery to make values that are arbitrary arrays and objects

I've got an HTML form that consists of a series of units like this:
<input name="categoryColor[]" />
<input name="categoryName[]" />
Using this jQuery code, I can capture this data and return it in an object like this:
{categoryColor: [array of values],
categoryName: [array of values]}
Here's an example of the code in action:
const getFormDataFromElem = function($elem, options) {
options = options || {};
const vis = options.onlyVisible ? ":visible" : "";
const formInputs = $elem.find(`:input${vis}, [contenteditable=true]${vis}`);
const data = {};
formInputs.each(function() {
const $this = $(this)
const type = $this.attr('type');
const val = type === "checkbox" ? (this.checked ? "1" : "0") :
($this.is('[contenteditable=true]') ? $this.text() : this.value);
const name0 = $this.attr('name');
const doArray = name0 && name0.slice(-2) === "[]";
const name = doArray ? name0.slice(0, -2) : name0;
if (!name || (!options.saveEmpty && !doArray && val === "")) {
return;
}
if (doArray) {
if (data.hasOwnProperty(name)) {
data[name].push(val);
return
}
data[name] = [val];
return;
}
data[name] = val;
});
return data;
};
const data = getFormDataFromElem($('.input'));
$('.output').text(JSON.stringify(data, null, 2));
.output {
font-family: monospace;
white-space: pre;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h2>Input</h2>
<div class="input">
<input name="categoryName[]" value="phase1"/>
<input name="categoryColor[]" value="red"/>
<input name="categoryName[]" value="phase2"/>
<input name="categoryColor[]" value="green"/>
<input name="categoryName[]" value="phase3"/>
<input name="categoryColor[]" value="blue"/>
</div>
<h2>Output</h2>
<div class="output"></div>
BUT I'd like to be able to write the HTML form units like this
<input name="categories[].color" />
<input name="categories[].name" />
since I really need this data in this form:
{categories: [array of objects],
}
where the objects have the form {name: '<name of category>', color: '<color string>'}.
How would I rewrite my general-purpose form-capturing routine to produce values that are arbitrary arrays and objects?
Following assumes you are able to group each set of inputs that make up one object. Then rather than having to parse names use data attributes on the group container for the main object property name.
Still a bit unclear if this is what you are after but can also modify to suit more specific needs. I realize the names are not unique and not sure if that is an issue or not
const data = {};
$('.input').each(function(i){
const $cont = $(this),
{struct, prop} = $cont.data(),
inputs = $cont.find('input').toArray();
if(struct === 'obj'){
data[prop] = data[prop] || [];
const obj = inputs.reduce((a,c)=>({...a, [c.name]:c.value}),{})
data[prop].push(obj);
}
})
console.log(data)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="input" data-struct="obj" data-prop="otherCat">
<input name="name" value="phase1" />
<input name="color" value="red" />
</div>
<div class="input" data-struct="obj" data-prop="categories">
<input name="name" value="phase2" />
<input name="color" value="green" />
</div>
<div class="input" data-struct="obj" data-prop="categories">
<input name="name" value="phase3" />
<input name="color" value="blue" />
</div>

Sum value of multiples input number field jquery

i have multiple input number fields with the same class, and i have to sum them but when I try with my javascript i get always NaN result
var arrNumber = new Array(); //contain the number of specific input field
var totale;
$(".input-n-pro").bind('keyup mouseup', function () {
totale = 0;
$('.input-n-pro').each(function(){
var this_num = $(this).val();
totale = parseInt(this_num)+parseInt(totale);
})
console.log("totale="+totale);
});
The html of input is this, generated by php, one for every row of a table
<input type="number" name="<?php echo $data["name"];?>" min="0" max="500" placeholder="0" class="form-control input-xs input-n-pro" style="display: inline">
I don't know it won't work, it work with only js withous jquery but i have to get the id of every field to do that and i want to do that for everyone with the same class because they are dinamic fields
P.S. The other part of my work, is to get every name of those fields and store them so i can have an array in js where i have the name of input and his number value, but i don't know how to do because they are dinamic
You probably parsing something that is not an integer. Then the parseInt won't work and returns NaN. If you sum a NaN, then it stays a NaN, example:
// working testcase:
const testArray = ['2', '3', '4'];
let total = 0;
for (value of testArray) {
total += parseInt(value);
}
// returns 9
console.log(total);
// your testcase:
const testArray2 = ['2', '3', 'notANumber'];
let total2 = 0;
for (value of testArray2) {
total2 += parseInt(value);
}
// returns NaN since we are adding 2 + 3 + NaN = NaN
console.log(total2);
So the solution is to 'negate' the NaN by treating it as 0:
// solution:
const myArray = ['2', '3', 'notANumber', '4'];
let total = 0;
for (value of myArray) {
// treat NaN, undefined or any falsey values as 0.
total += parseInt(value) || 0;
}
// returns 9
console.log(total);
To integrate this concept in your code, you'll get something like:
let total = 0;
$('.input-n-pro').each(() => {
let valueInString = $(this).val();
let actualValue = parseInt(valueInString) || 0;
total += actualValue;
});
if one of inputs value is empty then parseInt returns NAN. So you can better do a check using IsNan function. if input is empty than assign 0. For example;
var x= parseInt($('#abc').val()); if (isNaN(x)) x = 0;
Part 1 and 2 of your question
The reason you get NaN is most probably that if any of the inputs has no value, asking for that value returns an empty string (form fields always return strings) "". parseInt("") returns NaN.
Using vanilla ECMAScript 6, the solution is a one-liner with the help of Array.prototype.reduce:
const sum = [...document.querySelectorAll('.input-n-pro')].reduce((acc, val) => acc += Number(val.value) || 0, 0);
For your second question, just use Array.prototype.map. Also a one-liner.
const theArr = [...document.querySelectorAll('.input-n-pro')].map(x => {return { name: x.name, value: parseInt(x.value) || 0 }});
Note: The Array spread operator [...document.querySelectorAll('.input-n-pro')] makes an array from the NodeList document.querySelectorAll returns, so you can use Array methods on the list (like reduce and map).
Example:
calc.addEventListener('click', () => {
const sum = [...document.querySelectorAll('.input-n-pro')].reduce((acc, val) => acc += Number(val.value) || 0, 0);
console.log(sum);
})
getArr.addEventListener('click', () => {
const theArr = [...document.querySelectorAll('.input-n-pro')].map(x => {return { name: x.name, value: parseInt(x.value) || 0 }});
console.log(theArr);
})
<input type="number" value="5" class="input-n-pro" name="a" />
<input type="number" value="3" class="input-n-pro" name="b" />
<!-- lets insert one input that contains no number -->
<input type="text" value="foo" class="input-n-pro" name="m" />
<input type="number" value="2" class="input-n-pro" name="c" />
<input type="number" value="11" class="input-n-pro" name="d" />
<input type="number" class="input-n-pro" name="e" />
<br />
<button id="calc" type="button">Calculate Sum</button>
<button id="getArr" type="button">Get Array of name-value pairs</button>
bind() has been deprecated => use on
arrNumber = [], //contain the number of specific input field
totale = 0;
doTotale(); // first round
$(".input-n-pro").on('keyup mouseup change', doTotale);
function doTotale()
{
totale = 0;
arrNumber.length = 0;
$('.input-n-pro').each(function()
{
let
name = $(this).attr('name'),
val = parseInt($(this).val(),10) || 0;
arrNumber.push( {name, val });
totale += val;
})
console.clear();
console.log("totale =",totale);
console.log("arrNumber =", JSON.stringify(arrNumber) );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
AA : <input type="number" name="AA" value="5" class="input-n-pro" /> <br>
BB : <input type="number" name="BB" value="3" class="input-n-pro" /> <br>
CC : <input type="text" name="CC" value="foo" class="input-n-pro" /> <br> <!-- lets insert one input that contains no number -->
DD : <input type="number" name="DD" value="2" class="input-n-pro" /> <br>
EE : <input type="number" name="EE" value="11" class="input-n-pro" /> <br>
FF : <input type="number" name="FF" class="input-n-pro" />

Don't append if string already contains OnChange

I have a javascript OnChange function on a column having textboxes which captures the name of each row in a column. I am appending all the names and storing in variable.
Now , suppose user clicks same textbox again , I don't want to append that name again.
var AppendedString = null;
function onChangeTest(textbox) {
AppendedString = AppendedString;
AppendedString = AppendedString + ';' + textbox.name;
// this gives null;txt_2_4;txt_2_6;txt_3_4;txt_2_4 and so on..and I don't want to append same name again , here it's txt_2_4
}
My Input text :
<input type="text" name="txt_<%=l_profileid %>_<%=l_processstepsequence%>" value="<%= l_comments%>" onfocus="this.oldvalue = this.value;" onchange="onChangeTest(this);this.oldvalue = this.value;">
Those rows seem to have unique names.
you can simply check if AppendedString already contains that name :
var AppendedString=''
function onChangeTest(textbox) {
if (!AppendedString.includes(textbox.name)) {
AppendedString += ';' + textbox.name;
}
}
Codepen Link
You can’t initialize AppendedString as null otherwise, the includes() method won’t be available
otherwise, you can give each row a unique ID, and store in an array IDs that already have been clicked by the user.
var AppendedString = '';
var clickedRows = [];
function onChangeTest(textbox) {
if (!clickedRows.includes(textbox.id)) {
AppendedString += ';' + textbox.name;
clickedRows.push(textbox.id)
}
}
var arr = [];
$("input[type='text']").on("click", function() {
var nowS = ($(this).attr('name'));
if (!(arr.indexOf(nowS) > -1)) {
arr.push(nowS)
}
console.log(arr)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="m1" name="lbl1">
<input type="text" id="m2" name="lbl2">
<input type="text" id="m3" name="lbl3">
Somewhat similar to your need,
var arr = [];
$("input[type='text']").on("click", function() {
var nowS = ($(this).attr('name'));
if (!arr.includes(nowS)) {
arr.push(nowS)
}
console.log(arr)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="m1" name="lbl1">
<input type="text" id="m2" name="lbl2">
<input type="text" id="m3" name="lbl3">
You can add flag your textboxes and ignore if it's clicked again. Like using jquery you can do something like this:
function onChangeTest(textbox) {
AppendedString = AppendedString;
if (!textbox.hasClass("clicked")){
AppendedString = AppendedString + ';' + textbox.name;
textbox.AddClass("clicked");
}
}

Check if there are multiple input fields with the same value

What is the simplest way to check with jQuery if we have multiple input fields on the page with the same value?
Thank you all!
You can iterate all input elements, store their value in a hash table, and check if the value was already there:
var hash = Object.create(null),
result = [].some.call(document.getElementsByTagName('input'), function(inp) {
if(hash[inp.value]) return true;
hash[inp.value] = true;
});
Get all the input elements, sort and check if there are duplicates.
var elements = document.getElementsByTagName("input")
var values = [];
for (var i = 0; i < elements.length; i++) {
values.push(elements[i].value);
}
var sortedValues = values.sort();
for (var o = 0; o < values.length-1; o++) {
if (values[o] == values[o+1])
alert ('Duplicate!');
}
You can loop thru all inputs and generate a data structure like below.
var inputs = {};
$("input").each(function(i, elem) {
if (inputs.hasOwnProperty(elem.value)) {
inputs[elem.value] += 1;
} else {
inputs[elem.value] = 1;
}
});
alert (JSON.stringify(inputs, null, 4))
A Demo
The solution is to write a loop and iterate through each input field for a possible match. If you're using jQuery, then it's actually very simple.
Let's say we have a simple HTML page with 3 input fields.
HTML:
<input type="text" name="input1">
<input type="text" name="input2>
<input type="text" name="input3">
Then we use the jQuery each() method to iterate over the fields. Mainly saying, we iterate over all the input fields and get their values. Then we again iterate through all the input fields (so were actually creating a nested loop) and check if any of them match the currently iterating input value.
jQuery:
var currentInput;
$("input").each(function(index) {
currentInput = $(this);
$("input").each(function(index) {
if currentInput.val() === $(this).val() {
alert("Error: input fields match found");
}
});
});
I would like to provide a more efficient answer when it comes to checking for duplicate values in multiple input fields. When it comes to comparing values we need to,
Iterate and keep the current element somewhere temporarily
Re-iterate and check against the previously kept value whether its a duplicate
When performing the step 2, we need to make sure that we skip comparing the previously kept (step 1) value against itself.
If I am not wrong, I have seen step 1 and 2 in all above answers but not the step 3.
The following code will do all those 3 steps.
var eqArr = [];
var currentInput;
$("input").each(function(k1, v1) {
if($(v1).val() != ''){
currentInput = $(v1);
$("input").each(function(k2, v2) {
if(k1 !== k2 &&
currentInput.val() === $(v2).val() &&
$.inArray($(this).attr('id'), eqArr) === -1){
eqArr.push($(this).attr('id'));
}
});
}
});
In the above code I am collecting id's of those input fields of those duplicates (in array). After performing the above logic, doing following simple check will tell you whether you have duplicates or not.
if(eqArr.length > 0){
//It means we have duplicates
}
var eqArr = [];
var currentInput;
$("input").each(function(k1, v1) {
if ($(v1).val() != '') {
currentInput = $(v1);
$("input").each(function(k2, v2) {
if (k1 !== k2 &&
currentInput.val() === $(v2).val() &&
$.inArray($(this).attr('id'), eqArr) === -1) {
eqArr.push($(this).attr('id'));
}
});
}
});
console.log(eqArr);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Input Field Duplicates</title>
</head>
<body>
<input type="text" name="input1" id="i1" value="bbb">
<input type="text" name="input2" id="i2" value="aaa">
<input type="text" name="input3" id="i3" value="aaa">
<input type="text" name="input3" id="i4" value="fff">
<input type="text" name="input3" id="i5" value="bbb">
<input type="text" name="input3" id="i6" value="ccc">
<input type="text" name="input3" id="i7" value="bbb">
<input type="text" name="input3" id="i8" value="bbb">
</body>
</html>

jQuery .val() not setting value

$('.remove-member').click(function () {
var toRemove = $(this).parent().text().slice(0, -1);
var members = $(this).parent().siblings('input[name=group-members]').val().split(' ');
$(this).parent().remove();
removeElement(members, toRemove);
members = members.join(' ');
$(this).parent().siblings('input[name=group-members]').val(members);
});
In the above, everything works until the last line (setting the value to the string contained in members). Displaying the variable members in the console displays the expected string, signifying that $(this).parent().siblings('input[name=group-members]') is traversing the DOM correctly. My HTML is below:
<form method='POST' action='action.php'>
<input type='text' value='[ GROUP NAME GOES HERE ]' name='group_name' />
<input type='text' name='add-member' />
<div class='group_member'>name01<span class='remove-member'>x</span>
</div>
<div class='group_member'>name02<span class='remove-member'>x</span>
</div>
<div class='group_member'>name03<span class='remove-member'>x</span>
</div>
<div class='group_member'>name04<span class='remove-member'>x</span>
</div>
<input type='text' value='name01 name02 name03 name04' name='group-members' />
<input type='Submit' value='Update' />
</form>
Directly referencing $('input[name=group-members]') is not an option due to the nature of the page.
removeElement function:
function removeElement(arr) {
var what, a = arguments,
L = a.length,
ax;
while (L > 1 && arr.length) {
what = a[--L];
while ((ax = arr.indexOf(what)) !== -1) {
arr.splice(ax, 1);
}
}
return arr;
}
$('.remove-member').click(function () {
var toRemove = $(this).parent().text().slice(0, -1);
var members = $(this).parent().siblings('input[name=group-members]').val().split(' ');
$(this).parent().remove();
removeElement(members, toRemove);
members = members.join(' ');
$(this).parent().siblings('input[name=group-members]').val(members);
});
You are removing the parent..
$(this).parent().remove();
So the call..
$(this).parent().siblings('input[name=group-members]').val(members);
Shouldn't work anymore because you just killed the containing DOM node.

Categories