En Gmail, el usuario puede hacer clic en una casilla de verificación en la lista de correo electrónico, mantener presionada la tecla Shift y seleccionar una segunda casilla de verificación. Luego, JavaScript seleccionará / deseleccionará las casillas de verificación que se encuentran entre las dos casillas de verificación.
Tengo curiosidad por saber cómo se hace esto. ¿Es esto JQuery o algún JavaScript básico (o complejo)?
javascript
gmail
Ascaloniano
fuente
fuente
Respuestas:
Escribí una demostración autónoma que usa jquery:
$(document).ready(function() { var $chkboxes = $('.chkbox'); var lastChecked = null; $chkboxes.click(function(e) { if (!lastChecked) { lastChecked = this; return; } if (e.shiftKey) { var start = $chkboxes.index(this); var end = $chkboxes.index(lastChecked); $chkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', lastChecked.checked); } lastChecked = this; }); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <html> <head> </head> <body> <input type="checkbox" id="id_chk1" class="chkbox" value="1" />Check 1<br/> <input type="checkbox" id="id_chk2" class="chkbox" value="2" />Check 2<br/> <input type="checkbox" id="id_chk3" class="chkbox" value="3" />Check 3<br/> <input type="checkbox" id="id_chk4" class="chkbox" value="4" />Check 4<br/> <input type="checkbox" id="id_chk5" class="chkbox" value="5" />Check 5<br/> <input type="checkbox" id="id_chk6" class="chkbox" value="6" />Check 6<br/> <input type="checkbox" id="id_chk7" class="chkbox" value="7" />Check 7<br/> </body> </html>
fuente
.prop('checked'
, no.attr('checked'
. jsFiddle: jsfiddle.net/dn4jv9a5Esto se hace a través de un javascript bastante simple.
Realizan un seguimiento de la identificación de la última casilla marcada y cuando se marca otra casilla de verificación, usan el atributo de evento shiftKey para ver si se mantuvo el turno al hacer clic en la casilla de verificación. Si es así, establecen la propiedad marcada de cada casilla de verificación entre las dos en verdadero.
Para determinar cuándo se marca una casilla, probablemente utilicen un evento onclick en las casillas de verificación
fuente
Recientemente, escribí un complemento de jQuery que proporciona esa característica y más.
Después de incluir el complemento, solo necesita inicializar el contexto de las casillas de verificación con el siguiente fragmento de código:
$('#table4').checkboxes({ range: true });
Aquí está el enlace a la documentación, demostración y descarga: http://rmariuzzo.github.io/checkboxes.js/
fuente
Parece que todas las respuestas que puedo encontrar en línea dependen completamente de jQuery para esto. JQuery agrega muy poca funcionalidad. Aquí hay una versión rápida que no requiere ningún marco:
function allow_group_select_checkboxes(checkbox_wrapper_id){ var lastChecked = null; var checkboxes = document.querySelectorAll('#'+checkbox_wrapper_id+' input[type="checkbox"]'); //I'm attaching an index attribute because it's easy, but you could do this other ways... for (var i=0;i<checkboxes.length;i++){ checkboxes[i].setAttribute('data-index',i); } for (var i=0;i<checkboxes.length;i++){ checkboxes[i].addEventListener("click",function(e){ if(lastChecked && e.shiftKey) { var i = parseInt(lastChecked.getAttribute('data-index')); var j = parseInt(this.getAttribute('data-index')); var check_or_uncheck = this.checked; var low = i; var high=j; if (i>j){ var low = j; var high=i; } for(var c=0;c<checkboxes.length;c++){ if (low <= c && c <=high){ checkboxes[c].checked = check_or_uncheck; } } } lastChecked = this; }); } }
Y luego inicialízalo siempre que lo necesites:
allow_group_select_checkboxes('[id of a wrapper that contains the checkboxes]')
fuente
Bueno, la publicación es bastante antigua, pero aquí hay una solución que acabo de encontrar: jQuery Field Plug-In
fuente
Obtuve esta solución de http://abcoder.com/javascript/jquery/simple-check-uncheck-all-jquery-function/ (ahora muerto) :
Código JavaScript y HTML
var NUM_BOXES = 10; // last checkbox the user clicked var last = -1; function check(event) { // in IE, the event object is a property of the window object // in Mozilla, event object is passed to event handlers as a parameter if (!event) { event = window.event } var num = parseInt(/box\[(\d+)\]/.exec(this.name)[1]); if (event.shiftKey && last != -1) { var di = num > last ? 1 : -1; for (var i = last; i != num; i += di) { document.forms.boxes['box[' + i + ']'].checked = true; } } last = num; } function init() { for (var i = 0; i < NUM_BOXES; i++) { document.forms.boxes['box[' + i + ']'].onclick = check; } }
<body onload="init()"> <form name="boxes"> <input name="box[0]" type="checkbox"> <input name="box[1]" type="checkbox"> <input name="box[2]" type="checkbox"> <input name="box[3]" type="checkbox"> <input name="box[4]" type="checkbox"> <input name="box[5]" type="checkbox"> <input name="box[6]" type="checkbox"> <input name="box[7]" type="checkbox"> <input name="box[8]" type="checkbox"> <input name="box[9]" type="checkbox"> </form> </body>
fuente
Inspirado por las excelentes respuestas proporcionadas, aquí hay una versión simple de JavaScript que se usa
Array.prototype
para obligar a los nodelistas a usar funciones de matriz, en lugar defor
bucles.(function () { // encapsulating variables with IIFE var lastcheck = null // no checkboxes clicked yet // get desired checkboxes var checkboxes = document.querySelectorAll('div.itemslist input[type=checkbox]') // loop over checkboxes to add event listener Array.prototype.forEach.call(checkboxes, function (cbx, idx) { cbx.addEventListener('click', function (evt) { // test for shift key, not first checkbox, and not same checkbox if ( evt.shiftKey && null !== lastcheck && idx !== lastcheck ) { // get range of checks between last-checkbox and shift-checkbox // Math.min/max does our sorting for us Array.prototype.slice.call(checkboxes, Math.min(lastcheck, idx), Math.max(lastcheck, idx)) // and loop over each .forEach(function (ccbx) { ccbx.checked = true }) } lastcheck = idx // set this checkbox as last-checked for later }) }) }())
<div class="itemslist"> <input type="checkbox" name="one" value="1"> <input type="checkbox" name="two" value="2"> <input type="checkbox" name="three" value="3"> <input type="checkbox" name="four" value="4"> <input type="checkbox" name="five" value="5"> </div>
fuente
Realmente me gustó el ejemplo de gyo y agregué un código para que funcione en todas las casillas de verificación con el mismo nombre.
También agregué un MutationObserver para que los eventos también se manejen en las casillas de verificación recién agregadas.
$(document).ready(function() { var previouslyClicked = {}; var rangeEventHandler = function(event) { if (event.shiftKey && previouslyClicked[this.name] && this != previouslyClicked[this.name]) { var $checkboxes = $('input[type=checkbox][name='+this.name+']').filter(':visible'); var start = $checkboxes.index( this ); var end = $checkboxes.index( previouslyClicked[this.name] ); // console.log('range', start, end, this, previouslyClicked[this.name]); $checkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', previouslyClicked[this.name].checked); } else { previouslyClicked[this.name] = this; } }; if ("MutationObserver" in window) { // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/MutationObserver to refresh on new checkboxes var mutationCallback = function(mutationList, observer) { mutationList.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeName == 'INPUT' && node.type == 'checkbox') { $(node).on('click.selectRange', rangeEventHandler); } }); }); }; var observer = new MutationObserver(mutationCallback); observer.observe(document, { childList: true, attributes: false, // since name is dynamically read subtree: true }); } $('input[type=checkbox][name]').on('click.selectRange', rangeEventHandler); });
<html> <head> </head> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div> First: <input type="checkbox" name="first"> <input type="checkbox" name="first"> <input type="checkbox" name="first"> <input type="checkbox" name="first"> <input type="checkbox" name="first"> </div> <div> Second: <input type="checkbox" name="second"> <input type="checkbox" name="second"> <input type="checkbox" name="second"> <input type="checkbox" name="second"> <input type="checkbox" name="second"> </div> </body> </html>
fuente
Tomé la versión jQuery de @BC. y lo transformó en una versión ES6, ya que el código en realidad está resolviendo el problema de manera bastante elegante, en caso de que alguien todavía se encuentre con esto ...
function enableGroupSelection( selector ) { let lastChecked = null; const checkboxes = Array.from( document.querySelectorAll( selector ) ); checkboxes.forEach( checkbox => checkbox.addEventListener( 'click', event => { if ( !lastChecked ) { lastChecked = checkbox; return; } if ( event.shiftKey ) { const start = checkboxes.indexOf( checkbox ); const end = checkboxes.indexOf( lastChecked ); checkboxes .slice( Math.min( start, end ), Math.max( start, end ) + 1 ) .forEach( checkbox => checkbox.checked = lastChecked.checked ); } lastChecked = checkbox; } ) ); }
fuente
Encontré la mejor solución que funciona tanto para seleccionar como para anular la selección de las casillas de verificación.
Utiliza un javascript y Jquery centrales.
$(document).ready(function() { var $chkboxes = $('.chkbox'); var lastChecked = null; $chkboxes.click(function(e) { if(!lastChecked) { lastChecked = this; return; } if(e.shiftKey) { var start = $chkboxes.index(this); var end = $chkboxes.index(lastChecked); $chkboxes.slice(Math.min(start,end), Math.max(start,end)+ 1).prop('checked', e.target.checked); } lastChecked = this; }); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <html> <head> </head> <body> <input type="checkbox" id="id_chk1" class="chkbox" value="1" />Check 1<br/> <input type="checkbox" id="id_chk2" class="chkbox" value="2" />Check 2<br/> <input type="checkbox" id="id_chk3" class="chkbox" value="3" />Check 3<br/> <input type="checkbox" id="id_chk4" class="chkbox" value="4" />Check 4<br/> <input type="checkbox" id="id_chk5" class="chkbox" value="5" />Check 5<br/> <input type="checkbox" id="id_chk6" class="chkbox" value="6" />Check 6<br/> <input type="checkbox" id="id_chk7" class="chkbox" value="7" />Check 7<br/> </body> </html>
fuente
Aquí también hay otra implementación similar a la selección múltiple de Outlook.
<script type="text/javascript"> function inRange(x, range) { return (x >= range[0] && x <= range[1]); } $(document).ready(function() { var $chkboxes = $('.chkbox'); var firstClick = 1; var lastClick = null; var range = []; $chkboxes.click(function(e) { if(!e.shiftKey && !e.ctrlKey) { $('#index-' + firstClick).prop('checked', false); firstClick = $chkboxes.index(this) + 1; if (firstClick !== null && firstClick !== ($chkboxes.index(this)+1)) { $('#index-' + firstClick).prop('checked', true); } } else if (e.shiftKey) { lastClick = $chkboxes.index(this) + 1; if ((firstClick < lastClick) && !inRange(lastClick, range)) { for (i = firstClick; i < lastClick; i++) { $('#index-' + i).prop('checked', true); } range = [firstClick, lastClick]; } else if ((firstClick > lastClick) && !inRange(lastClick, range)) { for (i = lastClick; i < firstClick; i++) { $('#index-' + i).prop('checked', true); } range = [lastClick, firstClick]; } else if ((firstClick < lastClick) && inRange(lastClick, range)) { for (i = 1; i < 100; i++) { $('#index-' + i).prop('checked', false); } for (i = firstClick; i < lastClick; i++) { $('#index-' + i).prop('checked', true); } range = [firstClick, lastClick]; }else if ((firstClick > lastClick) && inRange(lastClick, range)) { for (i = 1; i < 100; i++) { $('#index-' + i).prop('checked', false); } for (i = lastClick; i < firstClick; i++) { $('#index-' + i).prop('checked', true); } range = [lastClick, firstClick]; } } }); });
fuente
Esta es la solución jquery que escribí y uso:
chksel
chksel_index
Además, cada uno
checkbox
tiene un atributo llamadorg
que contiene el mismo índicevar chksel_last=-1; $('.chksel').click(function(ev){ if(ev.shiftKey){var i=0; if(chksel_last >=0){ if($(this).attr('rg') >= chksel_last){ for(i=chksel_last;i<=$(this).attr('rg');i++){$('.chksel_'+i).attr('checked','true')}} if($(this).attr('rg') <= chksel_last){for(i=$(this).attr('rg');i<=chksel_last;i++){$('.chksel_'+i).attr('checked','true')}} } chksel_last=$(this).attr('rg'); }else{chksel_last=$(this).attr('rg');}
})
fuente
esta solución funciona para mí, también basada en ajax para DataTables https://jsfiddle.net/6ouhv7bw/4/
<table id="dataTable"> <tbody> <tr> <td><input type="checkbox"></td> </tr> <tr> <td><input type="checkbox"></td> </tr> <tr> <td><input type="checkbox"></td> </tr> <tr> <td><input type="checkbox"></td> </tr> </tbody> </table> <script> $(document).ready(function() { var $chkboxes = $('#dataTable'); var $range = '#dataTable tbody'; var $first = false; var $indexWrapp = 'tr'; var lastChecked = null; var $checkboxes = 'input[type="checkbox"]'; $chkboxes.on('click',$checkboxes,function(e) { if ($first===false) { lastChecked = $(this).closest($indexWrapp).index(); lastCheckedInput = $(this).prop('checked'); $first=true; return; } if (e.shiftKey) { var start = lastChecked; var end = $(this).closest($indexWrapp).index(); $( $range+' '+$indexWrapp).each(function() { $currIndex=$(this).index(); if( $currIndex>=start && $currIndex<=end ){ $(this).find($checkboxes).prop('checked', lastCheckedInput); } }) } lastCheckedInput = $(this).prop('checked'); lastChecked = $(this).closest($indexWrapp).index(); }); </script>
fuente