\$\begingroup\$
\$\endgroup\$
I wrote a small multiple select interface in jQuery, and I'm looking for any feedback on code quality/usability.
It has to do the following:
- When check all is checked, all boxes must become checked
- When check all is unchecked, all boxes must become unchecked
- When all boxes become checked the check all box must become checked
- Then if one box is unchecked, the check all box must become unchecked
- When any box is checked or unchecked a count must be updated, and the item
tr
must toggle aselected
class. - If any checkbox is checked the tools button must appear
- If no checkbox is checked the filters button must appear
var showToolbar = function() {
$('[data-role="toolbar"]').show();
$('[data-role="filters"]').hide();
};
var showFilters = function() {
$('[data-role="toolbar"]').hide();
$('[data-role="filters"]').show();
};
$(document).on('ready page:load', function() {
$('[data-select="items"]').on('click', function() {
var checkAllBox = $(this),
checkOneBoxes = $('[data-select="item"]');
if ( checkAllBox.is(':checked') ) {
checkOneBoxes.prop('checked', true).trigger('change');
showToolbar();
} else {
checkOneBoxes.prop('checked', false).trigger('change');
showFilters();
}
});
$('[data-select="item"]').on('change', function() {
var checkbox = $(this),
tableRow = checkbox.parents('tr');
if ( checkbox.is(':checked') ) {
tableRow.addClass('selected');
} else {
tableRow.removeClass('selected');
}
var numberOfCheckedBoxes = $('[data-select="item"]:checked').length;
if ( numberOfCheckedBoxes > 0 ) {
showToolbar();
} else {
showFilters();
}
var numberOfUncheckedBoxes = $('[data-select="item"]').not(':checked').length;
if ( numberOfUncheckedBoxes === 0 ) {
$('[data-select="items"]').prop('checked', true);
} else {
$('[data-select="items"]').prop('checked', false);
}
var target = $('.items-selected'),
html = numberOfCheckedBoxes + ' ';
html += numberOfCheckedBoxes == 1 ?
target.data('text-singular') : target.data('text-plural');
target.html(html);
});
});
var showToolbar = function() {
$('[data-role="toolbar"]').show();
$('[data-role="filters"]').hide();
};
var showFilters = function() {
$('[data-role="toolbar"]').hide();
$('[data-role="filters"]').show();
};
$(document).on('ready page:load', function() {
$('[data-select="items"]').on('click', function() {
var checkAllBox = $(this),
checkOneBoxes = $('[data-select="item"]');
if ( checkAllBox.is(':checked') ) {
checkOneBoxes.prop('checked', true).trigger('change');
showToolbar();
} else {
checkOneBoxes.prop('checked', false).trigger('change');
showFilters();
}
});
$('[data-select="item"]').on('change', function() {
var checkbox = $(this),
tableRow = checkbox.parents('tr');
if ( checkbox.is(':checked') ) {
tableRow.addClass('selected');
} else {
tableRow.removeClass('selected');
}
var numberOfCheckedBoxes = $('[data-select="item"]:checked').length;
if ( numberOfCheckedBoxes > 0 ) {
showToolbar();
} else {
showFilters();
}
var numberOfUncheckedBoxes = $('[data-select="item"]').not(':checked').length;
if ( numberOfUncheckedBoxes === 0 ) {
$('[data-select="items"]').prop('checked', true);
} else {
$('[data-select="items"]').prop('checked', false);
}
var target = $('.items-selected'),
html = numberOfCheckedBoxes + ' ';
html += numberOfCheckedBoxes == 1 ? target.data('text-singular') : target.data('text-plural');
target.html(html);
});
});
body {
padding: 20px;
}
.toolbar {
display: none;
}
tr.selected > td {
background-color: whitesmoke;
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="row">
<div class="col-xs-6">
<div class="toolbar" data-role="toolbar">
<a href="#" class="btn btn-default">Tools</a>
</div>
<div class="filters" data-role="filters">
<a href="#" class="btn btn-default">Filters</a>
</div>
</div>
<div class="col-xs-6">
<div class="items-selected" data-text-singular="item selected" data-text-plural="items selected">0 items selected</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th colspan="2">
<input type="checkbox" data-select="items">
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="checkbox" data-select="item">
</td>
<td>
Hummus
</td>
</tr>
<tr>
<td>
<input type="checkbox" data-select="item">
</td>
<td>
Beirut
</td>
</tr>
<tr>
<td>
<input type="checkbox" data-select="item">
</td>
<td>
Tabouleh
</td>
</tr>
<tr>
<td>
<input type="checkbox" data-select="item">
</td>
<td>
Sidon
</td>
</tr>
<tr>
<td>
<input type="checkbox" data-select="item">
</td>
<td>
Fatouch Salad
</td>
</tr>
<tr>
<td>
<input type="checkbox" data-select="item">
</td>
<td>
Lebanon
</td>
</tr>
</tbody>
</table>
asked Oct 9, 2014 at 17:45
1 Answer 1
\$\begingroup\$
\$\endgroup\$
2
You can simplify this:
if ( numberOfUncheckedBoxes === 0 ) { $('[data-select="items"]').prop('checked', true); } else { $('[data-select="items"]').prop('checked', false); }
Like this:
$('[data-select="items"]').prop('checked', numberOfUncheckedBoxes === 0);
Similarly, if you add this helper function:
var showOrHideToolbar = function(show) {
if (show) {
showToolbar();
} else {
showFilters();
}
}
Then you could simplify this:
if ( checkAllBox.is(':checked') ) { checkOneBoxes.prop('checked', true).trigger('change'); showToolbar(); } else { checkOneBoxes.prop('checked', false).trigger('change'); showFilters(); }
Like this:
var checkAllChecked = checkAllBox.is(':checked');
checkOneBoxes.prop('checked', checkAllChecked).trigger('change');
showOrHideToolbar(checkAllChecked);
And this one:
if ( numberOfCheckedBoxes > 0 ) { showToolbar(); } else { showFilters(); }
Like this:
showOrHideToolbar(numberOfCheckedBoxes > 0);
answered Oct 9, 2014 at 20:54
-
1\$\begingroup\$ Great review. Thanks. One thing that bothers about this, coming from a Ruby background, is that JavaScript seems to float around. By that I mean it's not encapsulated in a class. So my project ends up having several files of such code floating around... it seems "messy" \$\endgroup\$Mohamad– Mohamad2014年10月09日 21:32:55 +00:00Commented Oct 9, 2014 at 21:32
-
\$\begingroup\$ To avoid JavaScript code floating around, look into frameworks like BackboneJS and AngularJS \$\endgroup\$janos– janos2014年10月09日 21:55:28 +00:00Commented Oct 9, 2014 at 21:55
default