I'm trying to solve probably a very common problem and have prepared a simplified test case demonstrating it and my efforts.
I'm trying to display several jQuery UI dialogs, each containing several checkboxes of the same name (fruits and candy in my test code below)
In each dialog I have 4 buttons: Save, Cancel, Select all and Deselect all:
The first 3 buttons are already working in my code.
The Update button will in fact call DataTable's fnDraw() function, that part is already working too. (And I don't want to save the checkboxes values on the server inbetween, I'd like to do everything on the client-side - I know, this is possible).
My problem is in implementing the Cancel button for the dialogs:
1) I should probably save a list of currently set checkboxes on the dialog open event? And then restore them on Cancel click? Is there some elegant jQuery-way for that?
2) I don't know, how to only process the checkboxes of the currently open dialog only.
Below is my current test code, it works instantly - thanks to Google CDN:
<html>
<head>
<style type="text/css" title="currentStyle">
@import "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/redmond/jquery-ui.css";
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript">
$(function() {
var buttons = {
Cancel: cancel,
Save: save,
'Deselect All': deselect,
'Select All': select
};
$('#fruits').dialog({
autoOpen: false,
modal: true,
buttons: buttons
});
$('#candy').dialog({
autoOpen: false,
modal: true,
buttons: buttons
});
});
function update() {
var boxes = new Array();
$(':checkbox').each(function() {
if ($(this).is(':checked')) {
boxes.push(
$(this).attr('name') +
'=' +
$(this).val()
);
}
});
alert('boxes: ' + boxes.join('&'));
}
function select() {
$(':checkbox').prop('checked', true);
}
function deselect() {
$(':checkbox').prop('checked', false);
}
function save() {
// XXX how to implement?
$(this).dialog('close');
}
function cancel() {
// XXX how to implement?
$(this).dialog('close');
}
</script>
</head>
<body>
<p><input type="button" value="Select fruits" onclick="$('#fruits').dialog('open');"></p>
<div id="fruits" title="fruits">
<p><label><input type="checkbox" name="fruits" value="apple">apple</label></p>
<p><label><input type="checkbox" name="fruits" value="banana">banana</label></p>
<p><label><input type="checkbox" name="fruits" value="pear">pear</label></p>
</div>
<p><input type="button" value="Select candy" onclick="$('#candy').dialog('open');"></p>
<div id="candy" title="candy">
<p><label><input type="checkbox" name="candy" value="toffee">toffee</label></p>
<p><label><input type="checkbox" name="candy" value="fudge">fudge</label></p>
</div>
<p><input type="button" onclick="update();" value="Update"></p>
</body>
</html>
UPDATE: Thanks to mootinator the following code is working, but I still have 2 minor issues/questions:
1) Is it possible to use open event instead of the custom openDialog()method?
2) My Deselect All and Select All buttons modify all checkboxes at the page - instead of modifying only those belonging to the current dialog. I wonder how to select only the latter ones? (somehow use $(this) in selectAll() and deselectAll())?
I've tried
function selectAll() {
$($(this) + ' :checkbox').prop('checked', true);
}
function deselectAll() {
$($(this) + ' :checkbox').prop('checked', false);
}
but get syntax error.
<html>
<head>
<style type="text/css" title="currentStyle">
@import "/css/demo_table_jui.css";
@import "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/redmond/jquery-ui.css";
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1/jquery-ui.min.js"></script>
<script type="text/javascript" src="/js/jquery.dataTables.min.js"></script>
<script type="text/javascript">
$(function() {
var buttons = {
Cancel: cancel,
Save: save,
'Deselect All': deselectAll,
'Select All': selectAll
};
$('#openCandy').button();
$('#openFruits').button();
$('#update').button();
$('#openCandy').click(function() {
openDialog('#candy');
});
$('#openFruits').click(function() {
openDialog('#fruits');
});
$('#fruits').dialog({
autoOpen: false,
modal: true,
buttons: buttons
});
$('#candy').dialog({
autoOpen: false,
modal: true,
buttons: buttons
});
});
function update() {
var boxes = new Array();
$(':checkbox').each(function() {
if ($(this).is(':checked')) {
boxes.push(
$(this).attr('name') +
'=' +
$(this).val()
);
}
});
alert('boxes: ' + boxes.join('&'));
}
function selectAll() {
$(':checkbox').prop('checked', true);
}
function deselectAll() {
$(':checkbox').prop('checked', false);
}
function openDialog(sel) {
$(sel).dialog('open');
$(sel + ' :checkbox').each(function() {
$(this).data('XXX', $(this).is(':checked'));
});
}
function cancel() {
$(this).find(':checkbox').each(function() {
$(this).prop('checked', $(this).data('XXX'));
});
$(this).dialog('close');
}
function save() {
$(this).dialog('close');
}
</script>
</head>
<body>
<p><input id="openFruits" type="button" value="Select fruits"></p>
<div id="fruits" title="fruits">
<p><label><input type="checkbox" name="fruits" value="apple">apple</label></p>
<p><label><input type="checkbox" name="fruits" value="banana">banana</label></p>
<p><label><input type="checkbox" name="fruits" value="pear">pear</label></p>
</div>
<p><input id="openCandy" type="button" value="Select candy"></p>
<div id="candy" title="candy">
<p><label><input type="checkbox" name="candy" value="toffee">toffee</label></p>
<p><label><input type="checkbox" name="candy" value="fudge">fudge</label></p>
</div>
<p><input id="update" type="button" onclick="update();" value="Update"></p>
</body>
</html>
UPDATE2: Actually I have a 3rd and bigger problem: the closing X-button on the top-right corner of the dialog doesn't work as it should (it saves instead of cancelling).
I've tried adding close: cancel, to both dialogs, but I get the runtime error in Chrome:
Uncaught RangeError: Maximum call stack size exceeded
f.event.remove
f.event.remove
f.fn.extend.unbind
a.extend.destroy
a.extend.destroy
a.widget.close
a.widget.bridge.a.fn.(anonymous function)
e.extend.each
e.fn.e.each
a.widget.bridge.a.fn.(anonymous function)
cancel
a.Widget._trigger
a.widget.close
a.widget.bridge.a.fn.(anonymous function)
.....etc....
UPDATE3: Probably because I call $(this).dialog('close') in a loop?
I don't see an easy way to fix it though: if I create a separate function
function restore() {
$(this).find(':checkbox').each(function() {
$(this).prop('checked', $(this).data('XXX'));
});
}
function cancel() {
restore();
$(this).dialog('close');
}
and pass it as close: restore to dialogs, then the Save button breaks
I made a couple of modifications to your code. Probably the easiest thing to do (not necessarily the best) would be to save the state in a global variable. (A more robust solution might just involve saving the state alongside the dialog state/options).
UPDATE: Cleaned up the solution to store the initial state on the checkbox itself in the DOM instead of in a global variable.
http://jsfiddle.net/rhdNH/8/
I added a custom open function to facilitate saving the state, and completed the cancel function. You may want to also clean up the 'original' properties whenever you close using removeProp
, but it isn't strictly necessary.
Here are the changes you would make for point #1 (open:openDialog) in order to not have to call openDialog directly.
$('#fruits').dialog({
autoOpen: false,
modal: true,
buttons: buttons,
open: openDialog
});
$('#candy').dialog({
autoOpen: false,
modal: true,
buttons: buttons,
open: openDialog
});
And this is what your select/deselect should look like to only act on the open dialog:
function select() {
$(':checkbox', this).prop('checked', true);
}
function deselect() {
$(':checkbox', this).prop('checked', false);
}
And here is openDialog
edited to use this
instead of the jQuery selector:
function openDialog() {
$(':checkbox', this).each(function() {
$(this).prop('original', $(this).is(':checked'));
});
}
function cancel() {
$(this).find('input[type="checkbox"]').each(function() {
$(this).prop('checked', $(this).prop('original'));
});
$(this).dialog('close');
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With