I am having some problems regarding the jquery event handler function. I couldn't understand how can I set it in the correct way.
I will explain my problem, I have three checkboxes: 3D, TRI-Planar, and MPR. And when users check the 3D option the following two checkboxes appear Volume and Sur. Furthermore, when the user clicks the vol checkbox, some options toggle. And when the user unclicks the vol disappear and again if they click them then there will be two options of same. How can I solve it?
Below I have provided a minimal example which I used first without using a class like desire_viewer and method_selection. If you click 3D then vol and sur options toggle and if you click vol options then another options toggle but when u unclick it then it disappears and then click it again then two same options appear. I think there is something wrong with the code.
I expect the output to be like this: If the user clicks 3D options then it should toggle Volume and Surface options and again if the user clicks on the volume checkbox then volume options should toggle vice-verse with the surface. When the user unchecks any checkbox then its process should stop. For example, at first, the user clicked 3D > VOL and then 3D > sur, in this case, the first step should be stopped when the sur checkbox is clicked. I mean like logic 0 and 1. If the user clicks Tri-Planar then it's 1 and its option should toggle and again if the user unchecks it which is 0 then it's processed and should be stopped. So, in the next step user can play with MPR or other checkboxes.
ID_3D_render_selection = "#v1"
ID_tri_planar = "#v2"
ID_mpr_selection = "#v3"
ID_vol_selection = "#r1"
ID_sur_selection = "#r2"
$(ID_3D_render_selection).change(function() {
$('#select_render_method').slideToggle("slow");
$(ID_vol_selection).change(function() {
$('#VOL_OPTIONS').slideToggle("slow");
var vol_arr = []
var vol_arr2 = []
$( "#btn1" ).change(function() {
var vol_myFile = $('#btn1').prop('files');
vol_arr.push(vol_myFile)
});
<!--//////////////////////////////////////-->
$(document).ready(function() {
var vol_opacity = $('<input class=vol_set_opacity id="setScalarOpacityUnitDistance0" type="range" min="0" max="100" step="0.5" value="3">').appendTo('#set_opacity_distance_bm_Color');
var vol_distance = $('<input class=vol_set_distance id="setSampleDistance0" type="range" min="0.1" max="10" step="0.1" value="0.4">').appendTo('#set_opacity_distance_bm_Color');
var vol_blending = $('<select class=vol_blending_mode id=blendMode0 >').appendTo('#set_opacity_distance_bm_Color');
vol_blending.append($("<option>").attr('value',"0").text("Composite"));
var sel = $('<select class=colors_channels >').appendTo('#set_opacity_distance_bm_Color');
sel.append($("<option>").attr('value',"Reds").text("Reds"));
sel.append($("<option>").attr('value',"Blues").text("Blues"));
sel.append($("<option>").attr('value',"Greens").text("Greens"));
$( "#f" ).change(function() {
$('.vol_set_opacity').remove();
$('.vol_set_distance').remove();
$('.vol_blending_mode').remove();
$('.colors_channels').remove();
for(i=0; i<$('#f').val(); i++) {
var vol_opacity = $('<input class=vol_set_opacity id="setScalarOpacityUnitDistance'+ i +'"'+ ' type="range" min="0" max="100" step="0.5" value="3">').appendTo('#set_opacity_distance_bm_Color');
var vol_distance = $('<input class=vol_set_distance id="setSampleDistance'+ i + '"' + 'type="range" min="0.1" max="10" step="0.1" value="0.4">').appendTo('#set_opacity_distance_bm_Color');
var vol_blending = $('<select class=vol_blending_mode id="blendMode'+ i +'"'+ ' >').appendTo('#set_opacity_distance_bm_Color');
vol_blending.append($("<option>").attr('value',"0").text("Composite"));
var sel = $('<select class=colors_channels >').appendTo('#set_opacity_distance_bm_Color');
sel.append($("<option>").attr('value',"Reds").text("Reds"));
sel.append($("<option>").attr('value',"Blues").text("Blues"));
sel.append($("<option>").attr('value',"Greens").text("Greens"));
}
})
});
<!--//////////////////////////////////////-->
$( "#btn2" ).click(function() {
var vol_Picked_color = $(".colors_channels");
for(var i = 0; i < vol_Picked_color.length; i++){
vol_arr2.push($(vol_Picked_color[i]).val() );
}
console.log(vol_arr2)
if (vol_arr.length==vol_arr2.length){
vol_processFile(vol_arr, vol_arr2)
} else {
alert("Please check the number of input vs the number of channels ")
}
});
});
});
var tri_arr =[]
$(ID_tri_planar).click(function() {
$('#TRI_PLANAR_OPTIONS').slideToggle("slow");
});
$( "#btn1" ).change(function() {
var tri_myFile = $('#btn1').prop('files');
tri_arr.push(tri_myFile)
});
$( "#btn2" ).click(function() {
tri_processFile(tri_arr)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript" src="{% static '/js/jquery-3.6.0.min.js' %}"></script>
<div >
<input class="desire_viewer" type="checkbox" name="Viewers" id="v1" value="3D"><label for="v1">3D</label>
<input class="desire_viewer" type="checkbox" name="Viewers" id="v2" value="TRI-Planar"><label for="v2">TRI-Planar</label>
<input class="desire_viewer" type="checkbox" name="Viewers" id="v3" value="MPR"><label for="v3">MPR</label>
</div>
<div id="select_render_method" class="section_header_2" style="display:none;">
<input class="method_selection" type="checkbox" name="Render" id="r1" value="Vol" ><label for="r1">Vol</label>
<input class="method_selection" type="checkbox" name="Render" id="r2" value="Sur" ><label for="r2">Sur</label>
</div>
<div id="divInput" class="section_internal_layout_card_middle_body_title_4" >
<table>
<tbody>
<td>Select the number of inputs:</td>
<td>
<input min=1 max=10 type="number" id="f" value="1" style="width: 43px; height: 25px;">
</td>
</tbody>
</table>
<div>
<input name="inputFile" type="file" multiple id="btn1" style="margin-left: 1px; margin-top: 30px; padding: 0px; border: none; z-index: 1;">
</div>
<div>
<button name="render" id="btn2" style="margin-top: 0px; margin-left:304px; width: 96px; font-size: 14pt; border: none; z-index: 1; margin-bottom: 7px;"> Render </button>
</div>
</div>
<div id="VOL_OPTIONS" class="section_header_5" style="display:none;">
<div id="set_opacity_distance_bm_Color" class="section_internal_layout_card_middle_body_title_5">
<p><b>Scalar Opacity</b>&ensp<b>SampleDistance</b><b>Blending</b><b>Color</b></p>
</div>
</div>
<div id="SUR_OPTIONS" class="section_header_6" style="display:none;">
<div id="set_iso_Color" class="section_internal_layout_card_middle_body_title_55">
<p><b>Scalar Opacity</b><b>Iso value</b><b>Color</b> </p>
</div>
</div>
<div id="TRI_PLANAR_OPTIONS" class="section_header_7" style="display:none;">
<table>
<tbody>
<tr>
<td>XY</td>
<td>
<input class="XY" type="range" min="0" max="119" step="1" value="0"> <!-- sliceI -->
</td>
</tr>
<tr>
<td>XZ</td>
<td>
<input class="XZ" type="range" min="0" max="119" step="1" value="0"> <!-- sliceJ -->
</td>
</tr>
<tr>
<td>YZ</td>
<td>
<input class="YZ" type="range" min="0" max="119" step="1" value="0"> <!-- sliceK -->
</td>
</tr>
<tr>
<td>Color level</td>
<td>
<input class="colorLevel" type="range" min="0" max="255" step="1" value="0">
</td>
</tr>
<tr>
<td>ColorWindow</td>
<td>
<input class="colorWindow" type="range" min="0" max="255" step="1" value="0">
</td>
</tr>
</tbody>
</table>
</div>
<div id="MPR_OPTIONS" class="section_header_8" style="height:412px; display:none;">
<table><tbody><tr> // do some stuff </tr></tbody></table>
</div>
UPDATE:
OP has edited their question significantly and much of my original answer now makes no sense. Here's a new answer for the current code.
Leaving my original answer below for reference.
The main problem in the new code is that your volume toggle actions are not balanced - the untick action does not do the reverse of the tick action.
When you tick the volume checkbox, you add some HTML to the page, display it, and set up some new change handlers;
When you untick that same checkbox, you add the same HTML again, hide it, and add another set of identical change handlers on top of the first set;
So you can see that if you tick to volume checkbox, untick it, and then tick it again, you will see 2x your HTML on the page.
The other major problem is what I described in my original answer below as "problem 2" - you are adding event handlers inside event handlers. In the example tick/untick/tick example of the volume checkbox above, you will end up with 2x handlers for #f, and 2x handlers for #btn1. If, for eg, you click #btn1, that code will now run 2x, simultaneously. This gets very messy very quickly, and will cause all kinds of problems.
Here's updated, working code, with comments.
Note I have simplified the code a lot by removing lots of stuff which is not relevant to the current problem. Your question summaries the key problem:
... and when the user unclicks the vol disappear and again if they click them then there will be two options of same. How can I solve it?
Ticking and unticking the volume checkbox shows 2x duplicate options. That's the problem we're tying to solve. Everything else here is not relevant, and we can remove it. It is much simpler - for you too! - to find and fix the problem when you focus on just the part that is not working. This is what the minimal in MVCE refers to.
// Document ready event handler should never be nested inside other handlers.
$(document).ready(function() {
// Volume-related variables we need to be able to access later
var vol_opacity, vol_distance, vol_blending, sel;
// Click and change events are technically the same for checkboxes, but still be,
// consistent - use change here, not a mix of change and click as your code had.
// https://stackoverflow.com/questions/11205957/jquery-difference-between-change-and-click-event-of-checkbox
$('#v1').change(function() {
$('#select_render_method').slideToggle("slow");
});
$("#v2").change(function() {
$('#TRI_PLANAR_OPTIONS').slideToggle("slow");
});
// Do not nest event handlers inside each other - move this handler outside other
// change handlers
$('#r1').change(function() {
// We are toggling elements on and off here. If you are ADDing the HTML when
// the checkbox is ticked, it means you have to REMOVE that HTML when it is
// unticked. Is it really necessary? Modifying the DOM like this is slow and
// inefficient, what about just toggling visibility, like you do with
// slideToggle() for other options?
// Anyway - assuming you want to add/remove it, let's do it like this:
if ($(this).is(':checked')) {
addVolumeStuff();
} else {
deleteVolumeStuff();
}
// I moved this toggle below the code above - .appendTo is synchronous, so
// wait until the HTML updates are done before displaying them.
$('#VOL_OPTIONS').slideToggle("slow");
});
/**
* Add some HTML when the vol checkbox is ticked
*/
function addVolumeStuff() {
vol_opacity = $('<input class=vol_set_opacity id="setScalarOpacityUnitDistance0" type="range" min="0" max="100" step="0.5" value="3">').appendTo('#set_opacity_distance_bm_Color');
vol_distance = $('<input class=vol_set_distance id="setSampleDistance0" type="range" min="0.1" max="10" step="0.1" value="0.4">').appendTo('#set_opacity_distance_bm_Color');
vol_blending = $('<select class=vol_blending_mode id=blendMode0 >').appendTo('#set_opacity_distance_bm_Color');
vol_blending.append($("<option>").attr('value',"0").text("Composite"));
sel = $('<select class=colors_channels >').appendTo('#set_opacity_distance_bm_Color');
sel.append($("<option>").attr('value',"Reds").text("Reds"));
sel.append($("<option>").attr('value',"Blues").text("Blues"));
sel.append($("<option>").attr('value',"Greens").text("Greens"));
}
/**
* Delete the volume controls when vol checkbox is unticked
*/
function deleteVolumeStuff() {
vol_opacity.remove();
vol_distance.remove();
vol_blending.remove();
sel.remove();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="desire_viewer" type="checkbox" name="Viewers" id="v1" value="3D">3D
<input class="desire_viewer" type="checkbox" name="Viewers" id="v2" value="TRI-Planar">TRI-Planar
<input class="desire_viewer" type="checkbox" name="Viewers" id="v3" value="MPR">MPR
</div>
<div id="select_render_method" class="section_header_2" style="display:none;">
<input class="method_selection" type="checkbox" name="Render" id="r1" value="Vol" >Vol
<input class="method_selection" type="checkbox" name="Render" id="r2" value="Sur" >Sur
</div>
<div>
<input min=1 max=10 type="number" id="f" value="1">
<div>
<input name="inputFile" type="file" multiple id="btn1">
</div>
<div>
<button name="render" id="btn2">Render</button>
</div>
</div>
<div id="VOL_OPTIONS" style="display:none;">
<div id="set_opacity_distance_bm_Color">
<p><b>Scalar Opacity</b> <b>SampleDistance</b> <b>Blending</b> <b>Color</b></p>
</div>
</div>
<div id="SUR_OPTIONS" style="display:none;">
<div id="set_iso_Color">
<p><b>Scalar Opacity</b> <b>Iso value</b> <b>Color</b></p>
</div>
</div>
<div id="TRI_PLANAR_OPTIONS" style="display:none;">
<table>
<tbody>
<tr>
<td>XY</td>
<td>
<input class="XY" type="range" min="0" max="119" step="1" value="0">
</td>
</tr>
<tr>
<td>... etc ...</td>
<td> </td>
</tr>
</tbody>
</table>
</div>
Original answer
Problem 1:
var value = $("input[name='Viewers']:checked").val();
The selector will match all 3 of your checkboxes. But what will the .val() of 3 elements look like? Quoting the docs for .val():
Get the current value of the first element in the set of matched elements.
So you're only ever going to get one of your checkbox values, the first checked one. Try it:
$('.desire_viewer').on('click', function() {
console.log($('.desire_viewer:checked').val());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="desire_viewer" type="checkbox" name="Viewers" value="3D">3D
<input class="desire_viewer" type="checkbox" name="Viewers" value="TRI-Planar">TRI-Planar
<input class="desire_viewer" type="checkbox" name="Viewers" value="MPR">MPR
So how do you check if a particular checkbox is checked? As you can imagine this is a pretty common problem and there are a lot of duplicates here, eg:
Getting all selected checkboxes in an array
Get checkboxes (with the same name) as array
Send same name multiple checkbox values via ajax
You need to iterate over each of the inputs, like so:
$('.desire_viewer').on('click', function() {
console.log('These are now checked:');
$('.desire_viewer:checked').each(function(i) {
console.log(i, ':', $(this).val());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="desire_viewer" type="checkbox" name="Viewers" value="3D">3D
<input class="desire_viewer" type="checkbox" name="Viewers" value="TRI-Planar">TRI-Planar
<input class="desire_viewer" type="checkbox" name="Viewers" value="MPR">MPR
Note that inside the loop, $(this) represents the current jQuery object in the loop.
So in your case, your code might look something like:
$('.desire_viewer').on('click', function() {
$('.desire_viewer:checked').each(function(i) {
var val = $(this).val();
if (value == "3D") {
// Do stuff ...
} else if (value == "TRI-Planar") {
// Do other stuff ...
} else if (value == "MPR") {
// Do other different stuff ...
}
});
});
Problem 2:
$( "#btn1" ).change(function() {
This adds an event handler to your button. From this point on, any time that button is changed this handler will notice, and that function code will fire.
That's fine and will work. The problem is where it is added - when a checkbox is clicked. If the user decides they made a mistake and UNticks the TRI-Planar checkbox, guess what happens? Another identical event handler will be added to the button. And the best part? They will both fire! The handler function, whatever it is, will run 2x, in parallel. They don't overwrite each other, they all stack up, and they all run.
The (simplest) solution is to add event handlers independent of user interaction or other changes on the page, so they can only be bound once. If the code that runs is somehow dependent on where/when it would be triggered, set that up in the handler. Eg if this button change should only do something if TRI-Planar is checked, have the button event handler check if that is true before doing anything. Eg:
$("#btn1").change(function() {
// Maybe this should only happen if a certain checkbox is checked
$('.desire_viewer:checked').each(function(i) {
var val = $(this).val();
if (value == "TRI-Planar") {
// Do stuff
}
});
});
// Rest of your code - handlers are independent of user interaction and
// will only be bound once.
$('.desire_viewer').on('click', function() {
// ...
Note another option is to add handlers wherever you like, and use .off() to remove them, so you can dynamically add/remove them throughout your code. For simple applications I don't think this extra complexity is necessary.
There are lots of questions here about this too:
Is it correct to put an event inside an event?
jQuery click events firing multiple times
why is jQuery click event firing multiple times
Minor suggestion:
It looks like this is part of a bigger applicaton, and it looks like you're trying to reduce code repetition with variables like ID_desire_viewer = '.desire_viewer' etc. That's a good start but since those represent jQuery selectors, you may as well go just a tiny bit further and cache the actual selector.
Every time you do something like $(ID_desire_viewer) jQuery scans the whole DOM again to find matches. For small applications/pages you probably won't notice the performance hit doing that, but it is good practice to avoid it in case your app grows, and just in terms of read- and maintain-ability, DRY, etc.
To avoid that, save the results of the first search by doing:
let $viewers = $('.desire_viewer');
// Then you can do:
$viewers.on('click', function() { ...
Some references about that:
Does jQuery do any kind of caching of "selectors"?
Store jquery selector in variable
Try this
$('input["type=checkbox"]').attr("checked",'false');
i hope it was useful !
I need help with adding a controll that checks that atleast one on the textareas is filled so that people wouldnt save blank forms. so it should controll that at least on element is checked and filled, otherwise it should give an error and wouldnt save. If anyone would have an idea how to do so, I would greatly appreciate it. The code that Im working with is down below (actually have more textareas but they are the same only with another names).
<tr>
<td valign="top" style='width: 300px;'>Family members help</td>
<%
elemText = xml.getElementFromXPath("//nursing_care/family_help/tekst");
%>
<td valign="top"><input <%=(elemText==null?"checked=\"checked\"":"") %> value="0" onclick="javascript:showText(this);" name="//nursing_care/family_help" type="radio" checked="checked">Valimata
<input <%=(elemText!=null?"checked=\"checked\"":"") %> value="1" onclick="javascript:showText(this);" name="//nursing_care/family_help" type="radio">Määratud</td>
<td>
<textarea style='width: 350px' style="display:<%=(elemText==null?"none":"block") %>" id="//nursing_care/family_help/tekst" name="//nursing_care/family_help/tekst"><%=(elemText!=null?elemText.getText():"") %></textarea>
</td>
<td><input style="display:<%=(elemText==null?"none":"block") %>" type="text" class="txt_left" id="//nursing_care/family_help/date" name="//nursing_care/family_help/date" value="<%=xml.getText("//nursing_care/family_help/date")%>" maxlength="10" size="10"
onchange="gnlDateValid(this,event); if(event.returnValue != false);" onfocus="gnlGotFocus(getCurrentDate(),this); inputChanged(this);" onkeydown="gnlKeyDown('00.00.0000',this,event);" /></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3"><input type="submit" class="button_save button" value="Salvesta" />
<input type="button" class="button" value="Sulge" onclick="window.close()" /></td>
</tr>
</tfoot>
And here is the function that shows/hides the textareas (just in case)
function showText(obj){
var elements = document.getElementsByName(obj.name);
var element = getNode(obj.name + "/tekst");
if (elements[0].checked)
element.style.display="none";
else
element.style.display="block";
var element = getNode(obj.name + "/date");
if (elements[0].checked)
element.style.display="none";
else
element.style.display="block";
}
Something like this should work.
Extend the submit button like this.
<input type="submit" class="button_save button" value="Salvesta" onclick="return submitCheck()"/>
and implement this function in your javascript file.
function submitCheck(){
var form = document.forms[0];
var textareas = form.getElementsByTagName("textarea");
for(var textarea in textareas){
if(textarea.value !== ""){
return true;
}
}
return false;
}
BTW i would recommend you to use jQuery when working with the HTML DOM ;-)
I have a list of items that need to be selected and take an action based on user's request.
User selects the items and click on one of the btns to do something on the items.
My code is as following but I am not sure how to complete it. I believe, need to put them in a form to be submitted or pass the but not sure how to have a form with two submit btns, (if I need to have ).
<body>
<p><b>Shopping cart</b></p>
<table>
<tbody>
<c:forEach items="${mycart.items}" var="item">
<tr>
<td>
<input type="checkbox" name="Items"
value="${item.ID}"/>
</td>
<td>
Name : ${item.name}
</td>
</tr>
</c:forEach>
</tbody>
</table>
checkout
Delete
you can easily have two <input type="submit" name="something" /> in one <form>
if you want to differentiate the actions, just use different name for each submit button
EDIT:
<form ...>
...
...
<input id="b1" type="submit" name="edit" value="Edit"/>
<input id="b2" type="submit" name="delete" value="Delete"/>
</form>
If the form above is submitted by clicking #b1, then your request will contain a parameter named "edit". If the submit is triggered by #b2, then it will contain "delete".
I think following script might let you obtain what items are checked.
With jQuery, you need implement your checkout() like this
function checkout() {
$('input[name="Items"]:checkbox').each(function() {
if ($(this).attr("checked")) {
alert($(this).val() + 'is checked');
} else {
alert($(this).val() + 'is not checked');
}
}
);
}
I have some radio buttons in a table. I want to show/hide certain divs in a sibling td when I select certain radio buttons.
Here's the code I have:
$("input[type='radio'].map").change(function () {
$(this).closest('tr').find('.agency-mapping').show();
$(this).closest('tr').find('.agency-new').hide();
});
$("input[type='radio'].new").change(function () {
$(this).closest('tr').find('.agency-mapping').hide();
$(this).closest('tr').find('.agency-new').show();
});
...
<tr>
<td></td>
<td>
<div>
<input type="radio" class="map" value="map" checked="checked" />
<input type="radio" class="new" value="new" />
</div>
</td>
<td>
<div class="agency-mapping">
</div>
<div class="agency-new" style="display:none">
</div>
</td>
</tr>
...
This works fine if I have a couple rows. But I have hundreds of rows, and the performance is really poor. I click a radio button and it takes 5-10 seconds to show/hide the div.
Is there a better way to do this?
You may use .on() to attach the event only on the parent element like <tbody> or <table> instead of having it on every radio button on your table. Like this:
$('tbody').on('click', 'input.map', function(){
...
});
Read "Direct and delegated events" here
. Hope that helps..
I have this table containing 3 radio buttons, I want to find out whether a particular radio button is check or not at given point of time.
<table align="center" width="100%" border="0">
<tbody>
<tr>
<td>
<input type="radio" name="compareRadio" value="all" checked="checked"/>
<label>View All Records</label>
</td>
<td>
<input type="radio" name="compareRadio" value="diff" />
<label>View Differences</label>
</td>
<td>
<input type="radio" name="compareRadio" id="patch" value="patches" />
<label>Compare Patches</label>
</td>
<td>
<input type="button" class="btn" value="Export Into Excel"/>
</td>
</tr>
</tbody>
</table>
I send a request to the server, when the result comes back I want to identify whether patches radio button is selected or not.
So I did something like this.. but it returns all radio button
$.post("/csm/compare.action",
{
sessiontoken: sessiontoken,
compareCategory: "system",
compareSubCategory:"patch",
xml1:absP[0],
xml2:absP[1]},
function(resdata)
{
comparePatchData=resdata;
comparePatchLoading=false;
if($("input:radio[name=compareRadio]").val()=="patches")
{
//Trigger click on radio button for "same" campare
$('input[name=compareRadio]:eq(2)').click(); //so that it refreshes the content
$("input[name=compareRadio]:eq(2)").attr("checked", true);
$('input[type="radio"]').removeAttr('disabled');
}
}
);
If you just want to know if it is checked or not, then you could do this:
if($('#patch:checked').length)
// It is checked.
Or:
if($('input[value=patches]:checked').length)
// It is checked.
The $() function returns an array of matched elements so you can check its length property to see how many things (if any) were matched.
References:
:checked selector
Attribute equals selector
To find out if particular checkbox is checked you can use jQuery's is():
if($('input[value=all]').is(':checked'))
{
//Yep, it's checked
}