Issue with using .extend on array inside a for loop - javascript

I have a set of checkboxes, and based on which items are selected, different upload fields will display. To facilitate this, I want to dynamically create an array that contains all the classes I want to fetch (without duplication).
I have created an object with the details:
var uploadReq = {
a: [".document-2"],
b: [".document-1", ".document-3"],
c: [".document-1"],
d: [".document-2", ".document-3"],
e: [],
f: [".document-3"]
};
In this example, if someone chose Category A and Category B, we should end up with an array something like [".document-2", ".document-1", ".document-3"] (order is unimportant).
I have an event listener like this:
$("#client-cat").change(function() {
var arr = $("#client-cat input");
var classes = [];
for(i=0; i<arr.length; i++) {
if(arr[i].checked) {
var value = arr[i].value;
var arr2 = uploadReq[value];
$.extend(classes, arr2);
}
};
console.log(classes);
})
HTML:
<form>
<div class="segment">
<label for="client-cat">Client category:</label>
<div id="client-cat">
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="a">
<label>Category A</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="b">
<label>Category B</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="c">
<label>Category C</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="d">
<label>Category D</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="e">
<label>Category E</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="f">
<label>Category F</label>
</div>
</div>
</div>
<div class="segment">
<div class="document-1">
<label for="document-1">Upload a copy of Document 1:</label>
<input type="file" id="document-1" name="1" accept=".pdf">
</div>
<div class="document-2">
<label for="document-2">Upload a copy of Document 2:</label>
<input type="file" id="document-2" name="2" accept=".pdf">
</div>
<div class="document-3">
<label for="document-3">Upload a copy of Document 3:</label>
<input type="file" id="document-3" name="3" accept=".pdf">
</div>
</div>
</form>
However, when I run the code with Category A and Category B checked, I only get [".document-1", ".document-3"].
I believe what is happening is that every time the for loop restarts, it is reverting to the original value for classes, instead of taking the value from the end of the loop and restarting it.
Research/attempted fixes:
Looked at this thread which discusses using $.extend to solve a similar problem (e.g. combine two arrays without catching duplicates)
Tested to see if it's a scoping issue by trying the code:
$("#client-cat").change(function() {
var arr = $("#client-cat input");
var classes = [];
for(i=0; i<arr.length; i++) {
if(arr[i].checked) {
classes.push("bob");
}
}
console.log(classes);
})
But the above logs an array with as many "bob"s as there are checkboxes, so I don't think it's an issue with the scope of class.
Considered other methods of combining the data. Example: push works, but I end up with arrays inside arrays, which isn't what I want. Example: map might do it, but doesn't clear out duplicates.
JSFiddle here.

$.extend is not the right way to append arrays. It merges objects by adding properties in the second (or later) object that aren't in the first object. But when you use arrays, both arrays have a 0 property, so the first element of the second array is not added to the first array.
The function for appending arrays is concat. It doesn't modify the array in place, you need to assign back to the variable.
$("#client-cat").change(function() {
var arr = $("#client-cat input:checked");
var classes = [];
arr.each(function() {
classes = classes.concat(uploadReq[this.value]);
});
console.log(classes);
})

jQuery.extend()
First param: An object that will receive the new properties if additional objects are passed in or that will extend the jQuery namespace if it is the sole argument.
Therefore, with arrays you're going to face problems.
You can use this approach: classes = [ ...classes, ...arr2]
var uploadReq = {
a: [".document-2"],
b: [".document-1", ".document-3"],
c: [".document-1"],
d: [".document-2", ".document-3"],
e: [],
f: [".document-3"]
};
$("#client-cat").change(function() {
var classes = [];
var arr = $("#client-cat input");
for (var i = 0; i < arr.length; i++) {
if (arr[i].checked) {
var value = arr[i].value;
var arr2 = uploadReq[value];
classes = [ ...classes, ...arr2];
}
}
console.log(classes);
});
.segment {
margin-bottom: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="checkbox-display.css">
</head>
<body>
<form>
<div class="segment">
<label for="client-cat">Client category:</label>
<div id="client-cat">
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="a">
<label>Category A</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="b">
<label>Category B</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="c">
<label>Category C</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="d">
<label>Category D</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="e">
<label>Category E</label>
</div>
<div>
<input type="checkbox" tabindex="0" name="client-cat" value="f">
<label>Category F</label>
</div>
</div>
</div>
<div class="segment">
<div class="document-1">
<label for="document-1">Upload a copy of Document 1:</label>
<input type="file" id="document-1" name="1" accept=".pdf">
</div>
<div class="document-2">
<label for="document-2">Upload a copy of Document 2:</label>
<input type="file" id="document-2" name="2" accept=".pdf">
</div>
<div class="document-3">
<label for="document-3">Upload a copy of Document 3:</label>
<input type="file" id="document-3" name="3" accept=".pdf">
</div>
</div>
</form>
<script src="http://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous">
</script>
</body>
</html>

Related

Multiple elements to be called by a function

I have two radio buttons and a date picker and if I click or make changes to any of those three, all the values of the corresponding elements should be updated to an array. I've tried and failed.
Here is what I've created (jQuery):
if ($(["#submitDates"], ["input.usage"], ["input.scope"]).on("change")) {
var fromDate = $("#from_date").val();
var toDate = $("#to_date").val();
var usage = $('input.usage').val();
var scope = $('input.scope').val();
var data = {};
data.dateRange = `${fromDate}->${toDate}`;
data.scope = scope;
data.usage = usage;
console.clear();
console.log(data);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="col-md-2">
<input type="radio" class="usage" name="usages" value='email' checked> Email Usage
</div>
<div class="col-md-2">
<input type="radio" class="usage" name="usages" value='mail'> Mail Usage
</div>
<input type="radio" class="scope" name="scope" value="cm"> Current Month 
<input type="radio" class="scope" name="scope" value="q"> This Quarter 
<input type="radio" class="scope" name="scope" value="cy"> This Year 
<input type="text" class="form-control" id='from_date' name="start" placeholder="MM/DD/YYYY" />
<div class="input-group-append">
<span class="input-group-text bg-info b-0 text-white">TO</span>
</div>
<input type="text" class="form-control" id='to_date' name="end" placeholder="MM/DD/YYYY" /> 
<button class='btn btn-sm btn-success btn-circle' id="submitDates" style="border-radius: 50%"><i class='bi bi-check-lg' style='font-size: 16px;'></i></button>
There's quite a few issues in your code:
The selector in your jQuery object is wrong. Provide multiple selectors in a single comma delimited string, not multiple arguments containing strings in arrays.
Don't put a jQuery event handler in an if condition, it's useless
The change event handler syntax is wrong, you didn't provide the function argument which binds the handler to run when the event fires.
data is an object, not an array, as your title/question states
You need to read the val() from the selected .usage and .scope elements only.
  isn't a valid HTML character entitiy. I presume you mean instead, but even then this is redundant.
With those issues fixed, the code would look something like this:
let $fromDate = $("#from_date")
let $toDate = $("#to_date");
let $usage = $('input.usage');
let $scope = $('input.scope');
function handleFormUpdate() {
var data = {
dateRange: `${$fromDate.val()} -> ${$toDate.val()}`,
scope: $scope.filter(':checked').val(),
usage: $usage.filter(':checked').val()
};
console.log(data);
}
$('#submitDates').on('click', handleFormUpdate);
$('input.usage, input.scope').on("change", handleFormUpdate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="col-md-2">
<input type="radio" class="usage" name="usages" value="email" checked> Email Usage
</div>
<div class="col-md-2">
<input type="radio" class="usage" name="usages" value="mail"> Mail Usage
</div>
<input type="radio" class="scope" name="scope" value="cm"> Current Month
<input type="radio" class="scope" name="scope" value="q"> This Quarter
<input type="radio" class="scope" name="scope" value="cy"> This Year
<input type="text" class="form-control" id="from_date" name="start" placeholder="MM/DD/YYYY" />
<div class="input-group-append">
<span class="input-group-text bg-info b-0 text-white">TO</span>
</div>
<input type="text" class="form-control" id="to_date" name="end" placeholder="MM/DD/YYYY" />
<button class='btn btn-sm btn-success btn-circle' id="submitDates" style="border-radius: 50%">
<i class='bi bi-check-lg' style='font-size: 16px;'></i>
Check
</button>

How to remove checkboxes after matching values using jQuery?

I have 4 checkboxes if I select 1 check box then I will get 1 or more sub values and if I select 2nd check box then I will get 1 or more sub values Here My Problem is If I uncheck the 1st check box then I have to remove unchecked check box values not with second check box values().
$('.search-box1').on("click", function(e) {
var inputVal1 = $(this).val();
var cars = ["Saab", " Volvo", " BMW", " ABC", " HONDA", " TVS"];
$(".arrVal").html(cars);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<div class="row">
<div>
<label>First Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="First Page">
</div>
<div>
<label>Second Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="Second Page">
</div>
<div>
<label>Third Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="Third Page">
</div>
<div>
<label>Fourth Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="Fourth Page">
</div>
</div>
<div class="arrVal"></div>
You can construct your cars variable as object. Using the checkbox
value as key.
Use change as event
Use $('.search-box1:checked') selector to get all checked .search-box1 and use map to loop thru the objects.
Use join() to make the array into a string(comma seperated).
$('.search-box1').on("change", function(e) {
var inputVal1 = $(this).val();
var cars = {
value1: ["Saab", "Volvo", "BMW"],
value2: ["ABC", "HONDA", "TVS"],
value3: [],
value4: [],
value5: [],
}
var result = $('.search-box1:checked').map(function() {
return cars[this.value] || [];
}).get();
$(".arrVal").html(result.join());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<div class="row">
<div>
<label>First Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="value1">
</div>
<div>
<label>Second Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="value2">
</div>
<div>
<label>Third Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="value3">
</div>
<div>
<label>Fourth Page</label>
<input type="checkbox" name="txtCheck" id="txtCheck" class="search-box1" value="value4">
</div>
</div>
<div class="arrVal"></div>

Check if multiple radio buttons are checked

I'm not very good at Javascript, so I would like to ask help with the following:
I have a form, which has multiple radio groups (generated by php code, so I don't know their names OR how many will appear), and I need to check whether they are selected or not.
If not I want to show the user which question was not answered (no alert message, but it can be in text form or the question letters turning red).
I've tried googling the problem, but none of the previous answers were good to use in my case.
Here is my code so far:
function formCheck(formID) {
var eLabel=document.getElementById(formID).getElementsByTagName("label");
var radionames=[];
var eInput=document.getElementById(formID).getElementsByTagName("input");
var checker=true;
for (var i=0; i<eInput.length; i++) {
if (eInput[i].checked) {
radionames.push(eInput[i].name);
}
}
for (var i=0; i<eInput.length; i++) {
for (var j=0; j<radionames.length; j++) {
if (eInput[i]==radionames[j]) {
checker=true;
}
else {
alert();
checker=false;
}
}
}
return checker;
}
<form method="post" action="something.php" id="form1" name="form1">
<div class="que">que 1</div>
<div class="answ"><label><input name="2" value="7" type="radio">Answer 1</label></div>
<div class="answ"><label><input name="2" value="5" type="radio">Answer 2</label></div>
<div class="answ"><label><input name="2" value="8" type="radio">Answer 3</label></div>
<div class="answ"><label><input name="2" value="6" type="radio">Answer 4</label></div>
<div class="que">que 2</div>
<div class="answ"><label><input name="1" value="4" type="radio">Answer 1</label></div>
<div class="answ"><label><input name="1" value="1" type="radio">Answer 2</label></div>
<div class="answ"><label><input name="1" value="2" type="radio">Answer 3</label></div>
<div class="answ"><label><input name="1" value="3" type="radio">Answer 4</label></div>
<input class="submit_button" value="Submit the form" onclick="return formCheck('form1');" type="submit">
</form>
I wanted to create an array with the checked input "group" names, and compare it to all the input group names... the remaining ones will show the error (red text, a message, doesn't matter).
The problem is this code doesn't really do anything that I can see, and shows the something.php even if I don't have anything checked...
If this is not a good method, I'm open to any suggestions.
(I don't want to use jQuery, and the code has to run on older browsers too.)
Sorry for my english, it's not my native language &
Thanks for your help in advance!
A.
in second For loop in javascript :
use this line :
if (eInput[i].value == radionames[j]) {
instead of : if (eInput[i] == radionames[j]) {
you must realy get the value of eInput[i]
You can use document.querySelectorAll to get all input. You can also fine tune it by passing the type of input. Then filter out the name from the group of radio buttons
function getCheckedButton() {
var tempNames = [];
// get all radio button and loop through it to get it's name.
// use a tempArray to keep unique names
var radios = document.querySelectorAll('input').forEach(function(item) {
// if the name is not present then and only then adding name to the array
if (tempNames.indexOf(item.name) === -1) {
tempNames.push(item.name)
}
})
// now looping through temp array
for (var i = 0; i < tempNames.length; i++) {
// using the name to select the radio button group to check if any of radio
// button in this group is checked or not
// if not checked then it will give null
if (document.querySelector('input[name="' + tempNames[i] + '"]:checked') !== null) {
console.log(document.querySelector('input[name="' + tempNames[i] + '"]:checked').value)
} else {
console.log("Radio button of group value " + tempNames[i] + " is unchecked")
}
}
}
<div class="que">
que 1</div>
<div class="answ">
<label>
<input name="2" value="7" type="radio">Answer 1</label>
</div>
<div class="answ">
<label>
<input name="2" value="5" type="radio">Answer 2</label>
</div>
<div class="answ">
<label>
<input name="2" value="8" type="radio">Answer 3</label>
</div>
<div class="answ">
<label>
<input name="2" value="6" type="radio">Answer 4</label>
</div>
<div class="que">que 2</div>
<div class="answ">
<label>
<input name="1" value="4" type="radio">Answer 1</label>
</div>
<div class="answ">
<label>
<input name="1" value="1" type="radio">Answer 2</label>
</div>
<div class="answ">
<label>
<input name="1" value="2" type="radio">Answer 3</label>
</div>
<div class="answ">
<label>
<input name="1" value="3" type="radio">Answer 4</label>
</div>
<button onclick="getCheckedButton()">Get checked buttons</button>

Creating Forms in Javascript-Length is undefined

So I feel silly asking this question, but am currently a high school student in Coding that needs help. We're working on a project with the same requirements for all people, so I took some code that worked for my friend to use for a form; however, I keep running in the problem that my 'length is undefined' and therefore, will not do what I want it to. My code is below:
HTML:
What toppings do you like on your ice-cream?
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Whip Cream">Whip Cream
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Sprinkles">Sprinkles
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Fruit">Fruit
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Hot Fudge/Caramel">Hot Fudge/Caramel
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Other">Other
</label>
</div>
<input name="Submit" type="Submit" value="Submit">
<div id="r">
</div>
Script:
var form = document.forms.example;
//This points to the form called "example" in HTML
form.addEventListener("submit",nameDisplay,false);
function nameDisplay(event) {
event.preventDefault();
var person = {
name: form.username.value,
}
var text = "<p> Mmmm..." + person.name +" sounds yummy!</p>";
document.getElementById("result").innerHTML = text;
}
var l = [];
for(i = 0; i < form.food.length; i++) {
if(form.food[i].checked) {
l.push(form.food[i].value);
}
console.log("loop");
}
console.log(l);
person.food = l;
console.log(person.food);
var text = "<p>You like" + person.food.join(",") + "on your ice-cream.</p>";
document.getElementById("r").innerHTML = text;
NOTE: I have two forms, hence the first part of javascript, but I thought maybe the problem lies within one thing is overriding another and what not or I'm missing something. I am only having problems with the ice-cream one though. Please help! Thanks in advance!
Below is the working version of your code
Issues found:
form tag was missing
There was no username input yet person needed it
The code you added
after your friend's was outside the nameDisplay function
There was no "result" div
Other concerns you may want to review
Is there a need to wrap your input's in divs?
No need for the food variable
I'd love to see the loop replaced with a filter and some
Bro, are you sure im not doing your homework?
var form = document.forms.example; //This points to the form called "example" in HTML
form.addEventListener("submit", nameDisplay, false);
function nameDisplay(event) {
var food = [];
for (i = 0; i < form.food.length; i++) {
if (form.food[i].checked) {
food.push(form.food[i].value);
}
}
var text = "<p>You like " + food.join(",") + " on your ice-cream.</p>";
document.getElementById("r").innerHTML = text;
}
<h3>What would you like on your Ice Cream?</h3>
<form id="example">
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Whip Cream">Whip Cream
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Sprinkles">Sprinkles
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Fruit">Fruit
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Hot Fudge/Caramel">Hot Fudge/Caramel
</label>
</div>
<div class="checkbox">
<label>
<input name="food" type="checkbox" value="Other">Other
</label>
</div>
<input name="Submit" type="Submit" value="Submit">
<div id="r">
</div>
</form>

jQuery - Uncheck other checkboxes if a specific checkbox is selected by user

I would like to uncheck all the checkboxes that are presently selected if a specific checkbox is selected by the user.
Example:
<div>
<label for="foo">
<input type="checkbox" name="meh" id="foo" checked> foo
</label>
</div>
<div>
<label for="bar">
<input type="checkbox" name="meh" id="bar" checked> bar
</label>
</div>
<div>
<label for="foobar">
<input type="checkbox" name="meh" id="foobar"> foobar
</label>
</div>
<div>
<label for="barfoo">
<input type="checkbox" name="meh" id="barfoo" checked> barfoo
</label>
</div>
<div>
<label for="omgwtfbbq">
<input type="checkbox" name="meh" id="omgwtfbbq"> omgwtfbbq
</label>
</div>
If the user selects "omgwtfbbq" checkbox, I would like all the other boxes that might be checked to be unchecked and have the "omgwtfbbq" be the only one checked.
for the label instead of id I think you need for
<div>
<label for="foo">
<input type="checkbox" name="foo" id="foo" checked /> foo
</label>
</div>
<div>
<label for="bar">
<input type="checkbox" name="bar" id="bar" checked /> bar
</label>
</div>
<div>
<label for="foobar">
<input type="checkbox" name="foobar" id="foobar" /> foobar
</label>
</div>
<div>
<label for="barfoo">
<input type="checkbox" name="barfoo" id="barfoo" checked /> barfoo
</label>
</div>
<div>
<label for="omgwtfbbq">
<input type="checkbox" name="omgwtfbbq" id="omgwtfbbq" /> omgwtfbbq
</label>
</div>
then
var $others = $('input[type="checkbox"][name="meh"]').not('#omgwtfbbq')
$('#omgwtfbbq').change(function () {
if (this.checked) {
$others.prop('checked', false)
}
});
$others.change(function () {
if (this.checked) {
$('#omgwtfbbq').prop('checked', false)
}
})
Demo: Fiddle
Note: I'll add a common class to all the input elements which has to be affected by omgwtfbbq and change var $others = $('#foo, #bar, #foobar, #barfoo') to var $others = $('.myclassoninput')
Live demo (click).
$('#omgwtfbbq').click(function() {
$('input:checkbox').not(this).attr('checked', false);
});
Also note that you're re-using id's. Id's should only be used once in a document.
If you choose not to give each checkbox a sequential IDs so that you can use an array, here's a solution:
Place all your controls in a div, with an ID "checkgroup".
Then the JavaScript function goes:
function checkone(d){
if (!d.checked) return; //if it's unchecked, then do nothing
var group=document.getElementById('checkgroup');
var os=group.getElementsByTagName('input');
for (var i=0;i<os.length;i++){
if (os[i].checked&&os[i]!=d) os[i].checked=false;
}
}
Now you can call this function in each checkbox
<div id="checkgroup">
<input id="abcd" onclick="checkone(this);">
<input id="xyz" onclick="checkone(this);">
...
</div>
Note how you don't even need to bother with the name, because the object passes in itself.

Categories