html selecciona solo una casilla en un grupo

125

Entonces, ¿cómo puedo permitir que un usuario seleccione solo una casilla de verificación?

Sé que los botones de radio son "ideales", pero para mi propósito ... no lo es.

Tengo un campo en el que los usuarios deben seleccionar cualquiera de las dos opciones, pero no ambas. El problema es que necesito que mis usuarios también puedan deseleccionar su opción, y aquí es donde fallan los botones de opción porque una vez que selecciona el grupo, tiene que elegir una opción.

Validaré la información a través de php, pero todavía me gustaría restringir a los usuarios a una respuesta si quieren darla.

usuario962449
fuente
1
Solo con HTML, esto no se puede hacer. Necesitarás JavaScript. Si estás abierto a jQuery, puedo darte una solución rápida.
Surreal Dreams
12
¿Qué pasa con un botón de opción adicional etiquetado como "ninguno"?
FelipeAls
2
una tercera opción no va bien con mi diseño ... aunque es una buena alternativa :)
user962449
2
La casilla de verificación con una sola opción es en realidad un botón de opción. ¿Esto no sorprenderá a los usuarios?
Gherman
@Surreal Dreams Se podría hacer en HTML, mira mi respuesta. Sin embargo, en la mayoría de los casos, ese JS es más simple y no hay necesidad de hacks.
SamGoody

Respuestas:

179

Este fragmento hará lo siguiente:

  • Permitir agrupación como botones de radio
  • Actuar como radio
  • Permitir anular la selección de todos

// the selector will match all input controls of type :checkbox
// and attach a click event handler 
$("input:checkbox").on('click', function() {
  // in the handler, 'this' refers to the box clicked on
  var $box = $(this);
  if ($box.is(":checked")) {
    // the name of the box is retrieved using the .attr() method
    // as it is assumed and expected to be immutable
    var group = "input:checkbox[name='" + $box.attr("name") + "']";
    // the checked state of the group/box on the other hand will change
    // and the current value is retrieved using .prop() method
    $(group).prop("checked", false);
    $box.prop("checked", true);
  } else {
    $box.prop("checked", false);
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>


<div>
  <h3>Fruits</h3>
  <label>
    <input type="checkbox" class="radio" value="1" name="fooby[1][]" />Kiwi</label>
  <label>
    <input type="checkbox" class="radio" value="1" name="fooby[1][]" />Jackfruit</label>
  <label>
    <input type="checkbox" class="radio" value="1" name="fooby[1][]" />Mango</label>
</div>
<div>
  <h3>Animals</h3>
  <label>
    <input type="checkbox" class="radio" value="1" name="fooby[2][]" />Tiger</label>
  <label>
    <input type="checkbox" class="radio" value="1" name="fooby[2][]" />Sloth</label>
  <label>
    <input type="checkbox" class="radio" value="1" name="fooby[2][]" />Cheetah</label>
</div>

bPratik
fuente
3
El uso correcto sería usar $ (this) .is (": marcado") el "es" para verificar si la casilla de verificación se estaba marcando en el if {...} else {...} aquí ... jsfiddle .net / zGEaa / 31
sergioadh
2
Tenga en cuenta que .attr ya no funciona, use .prop ("marcado") en su lugar para las versiones más nuevas de jQuery
usuario871784
@ user871784 - Gracias por el aviso ... ¡He actualizado el violín!
bPratik
3
Te perdiste el selector de radio: $ ("input: checkbox.radio")
Sven
@Sven: sería un selector demasiado específico en este ejemplo. Dicho esto, si la página contiene otro conjunto de casillas de verificación que no deberían tener este comportamiento, .radiosería útil usar el selector. Gracias por señalarlo :)
bPratik
101

Debería vincular un change()controlador para que el evento se active cuando cambie el estado de una casilla de verificación. Luego, simplemente anule la selección de todas las casillas de verificación, aparte de la que activó el controlador:

$('input[type="checkbox"]').on('change', function() {
   $('input[type="checkbox"]').not(this).prop('checked', false);
});

Aquí hay un violín


En cuanto a la agrupación, si su casilla de verificación "grupos" eran todos hermanos:

<div>
    <input type="checkbox" />
    <input type="checkbox" />
    <input type="checkbox" />
</div>  
<div>
    <input type="checkbox" />
    <input type="checkbox" />
    <input type="checkbox" />
</div>   
<div>
    <input type="checkbox" />
    <input type="checkbox" />
    <input type="checkbox" />
</div>

Podrías hacer esto:

$('input[type="checkbox"]').on('change', function() {
   $(this).siblings('input[type="checkbox"]').prop('checked', false);
});

Aquí hay otro violín


Si sus casillas de verificación están agrupadas por otro atributo, como name:

<input type="checkbox" name="group1[]" />
<input type="checkbox" name="group1[]" />
<input type="checkbox" name="group1[]" />

<input type="checkbox" name="group2[]" />
<input type="checkbox" name="group2[]" />
<input type="checkbox" name="group2[]" />

<input type="checkbox" name="group3[]" />
<input type="checkbox" name="group3[]" />
<input type="checkbox" name="group3[]" />

Podrías hacer esto:

$('input[type="checkbox"]').on('change', function() {
    $('input[name="' + this.name + '"]').not(this).prop('checked', false);
});

Aquí hay otro violín

billyonecan
fuente
Me gusta tu (último) código. Muy corto y aún claro. No estaba seguro de si el 'cambio' se activaría al cambiar las otras casillas de verificación, pero no lo hice cuando lo intenté. Así que prefiero tu código. ¡Gracias! :)
Frank Fajardo
Realmente me gusta esto, tengo que hacer un pequeño ajuste para mi necesidad. Tengo dos elementos, por lo que el primer elemento está marcado de forma predeterminada y, si no está marcado, el segundo elemento queda marcado. Esto me ayudó a comenzar.
john.weland
Hola @ john.weland: ¿te refieres a algo como esto ?
billyonecan
@billyone puede ser casi exactamente pero con la capacidad de apuntar a un grupo dado. como este . Gracias
john.weland
2
más uno por simplicidad
Chad
26

Los botones de radio son ideales. Solo necesita una tercera opción "ninguno" que está seleccionada de forma predeterminada.

Quentin
fuente
1
Esa es una buena solución, pero prefiero mantener las casillas de verificación porque mi diseño no es ideal para una tercera opción.
user962449
66
Sugeriría encarecidamente cambiar el diseño. Marque 0 o 1 de estas 2 opciones no es un patrón común y no será tan intuitivo para los usuarios como Marque 1 de estas 3 opciones
Quentin
44
¿Por qué cambiaría mi diseño completo por 2 casillas de verificación?
user962449
9
Si tal cambio requiere que cambie "todo su diseño", eso sugiere que el diseño es demasiado inflexible en primer lugar.
Quentin
10
No es inflexible, simplemente no se ve bien ... Puede verse bien en formularios y aplicaciones, pero tenemos diferentes usos para nuestras casillas de verificación.
user962449
12

Ya hay algunas respuestas a esto basadas en JS puro, pero ninguna de ellas es tan concisa como me gustaría que fueran.

Aquí está mi solución basada en el uso de etiquetas de nombre (como con botones de radio) y algunas líneas de javascript.

function onlyOne(checkbox) {
    var checkboxes = document.getElementsByName('check')
    checkboxes.forEach((item) => {
        if (item !== checkbox) item.checked = false
    })
}
<input type="checkbox" name="check" onclick="onlyOne(this)">
<input type="checkbox" name="check" onclick="onlyOne(this)">
<input type="checkbox" name="check" onclick="onlyOne(this)">
<input type="checkbox" name="check" onclick="onlyOne(this)">

Evertvdw
fuente
Gracias, este lo hizo por mí de todos los demás =)
kaya
6
$("#myform input:checkbox").change(function() {
    $("#myform input:checkbox").attr("checked", false);
    $(this).attr("checked", true);
});

Esto debería funcionar para cualquier número de casillas de verificación en el formulario. Si tiene otros que no son parte del grupo, configure los selectores para las entradas aplicables.

Sueños surrealistas
fuente
sí señor :) Está bien, encontré algo que funciona para mí, aunque su solución parece bastante simple. Probablemente hice algo mal por mi parte. Gracias de todos modos.
user962449
5

Aquí hay una solución simple de HTML y JavaScript que prefiero:

// función js para permitir solo marcar una casilla de verificación de un día de la semana a la vez:

function checkOnlyOne(b){

var x = document.getElementsByClassName('daychecks');
var i;

for (i = 0; i < x.length; i++) {
  if(x[i].value != b) x[i].checked = false;
}
}


Day of the week:
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Monday" />Mon&nbsp;&nbsp;&nbsp;
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Tuesday" />Tue&nbsp;&nbsp;&nbsp;
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Wednesday" />Wed&nbsp;&nbsp;&nbsp;
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Thursday" />Thu&nbsp;&nbsp;&nbsp;
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Friday" />Fri&nbsp;&nbsp;&nbsp;
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Saturday" />Sat&nbsp;&nbsp;&nbsp;
<input class="daychecks" onclick="checkOnlyOne(this.value);" type="checkbox" name="reoccur_weekday" value="Sunday" />Sun&nbsp;&nbsp;&nbsp;<br /><br />
Ian de Jafty.com
fuente
4

Que este código te ayude.

$(document).ready(function(){
$('.slectOne').on('change', function() {
   $('.slectOne').not(this).prop('checked', false);
   $('#result').html($(this).data( "id" ));
   if($(this).is(":checked"))
   	$('#result').html($(this).data( "id" ));
   else
   	$('#result').html('Empty...!');
});
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

</head>
<body>
<input type="checkbox" class="slectOne" data-id="1 selected"/>
<input type="checkbox" class="slectOne" data-id="2 selected"/>
<input type="checkbox" class="slectOne" data-id="3 selected"/>
<input type="checkbox" class="slectOne" data-id="4 selected"/>
<input type="checkbox" class="slectOne" data-id="5 selected"/>
<input type="checkbox" class="slectOne" data-id="6 selected"/>
<input type="checkbox" class="slectOne" data-id="7 selected"/>
<input type="checkbox" class="slectOne" data-id="8 selected"/>
<input type="checkbox" class="slectOne" data-id="9 selected"/>
<input type="checkbox" class="slectOne" data-id="10 selected"/>
<span id="result"></span>
</body>
</html>

Enlace de trabajo Haga clic aquí

Om Shankar
fuente
3

A partir de la respuesta de billyonecan , puede usar el siguiente código si necesita ese fragmento para más de una casilla de verificación (suponiendo que tengan nombres diferentes).

    $('input.one').on('change', function() {
        var name = $(this).attr('name');
        $('input[name='+name+'].one').not(this).prop('checked', false);
    }); 
tcastrog10
fuente
3

Si bien JS es probablemente el camino a seguir, podría hacerse solo con HTML y CSS.

Aquí tienes un botón de radio falso que es realmente una etiqueta para un botón de radio oculto real. Al hacer eso, obtienes exactamente el efecto que necesitas.

<style>
   #uncheck>input { display: none }
   input:checked + label { display: none }
   input:not(:checked) + label + label{ display: none } 
</style>

<div id='uncheck'>
  <input type="radio" name='food' id="box1" /> 
  Pizza 
    <label for='box1'>&#9678;</label> 
    <label for='box0'>&#9673;</label>
  <input type="radio" name='food' id="box2" /> 
  Ice cream 
    <label for='box2'>&#9678;</label> 
    <label for='box0'>&#9673;</label>
  <input type="radio" name='food' id="box0" checked />
</div>

Véalo aquí: https://jsfiddle.net/tn70yxL8/2/

Ahora, eso supone que necesita etiquetas no seleccionables.

Si estaba dispuesto a incluir las etiquetas, técnicamente puede evitar repetir la etiqueta "desmarcar" cambiando su texto en CSS, consulte aquí: https://jsfiddle.net/7tdb6quy/2/

SamGoody
fuente
1

Ejemplo con AngularJs

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
  <script>
    angular.module('app', []).controller('appc', ['$scope',
      function($scope) {
        $scope.selected = 'other';
      }
    ]);
  </script>
</head>

<body ng-app="app" ng-controller="appc">
  <label>SELECTED: {{selected}}</label>
  <div>
    <input type="checkbox" ng-checked="selected=='male'" ng-true-value="'male'" ng-model="selected">Male
    <br>
    <input type="checkbox" ng-checked="selected=='female'" ng-true-value="'female'" ng-model="selected">Female
    <br>
    <input type="checkbox" ng-checked="selected=='other'" ng-true-value="'other'" ng-model="selected">Other
  </div>



</body>

</html>

DAS
fuente
1

Con javascript antiguo simple.

<html>
<head>
</head>
<body>
<input type="checkbox" name="group1[]" id="groupname1" onClick="toggle(1,'groupname')"/>
<input type="checkbox" name="group1[]" id="groupname2" onClick="toggle(2,'groupname')"  />
<input type="checkbox" name="group1[]" id="groupname3" onClick="toggle(3,'groupname')" />

<input type="checkbox" name="group2[]" id="diffGroupname1" onClick="toggle(1,'diffGroupname')"/>
<input type="checkbox" name="group2[]" id="diffGroupname2" onClick="toggle(2,'diffGroupname')"  />
<input type="checkbox" name="group2[]" id="diffGroupname3" onClick="toggle(3,'diffGroupname')" />
<script>
function toggle(which,group){
var counter=1;
var checkbox=document.getElementById(group+counter);
while(checkbox){
if(counter==which){

}else{
checkbox.checked=false;
}
counter++;
checkbox=document.getElementById(group+counter);
}
}
</script>
</body>
</html>
Solomon P Byer
fuente
0

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>

<head>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
  <script>
    angular.module('app', []).controller('appc', ['$scope',
      function($scope) {
        $scope.selected = 'male';
      }
    ]);
  </script>
</head>

<body ng-app="app" ng-controller="appc">
  <label>SELECTED: {{selected}}</label>
  <div>
    <input type="checkbox" ng-checked="selected=='male'" ng-true-value="'male'" ng-model="selected">Male
    <br>
    <input type="checkbox" ng-checked="selected=='female'" ng-true-value="'female'" ng-model="selected">Female
    <br>
    <input type="checkbox" ng-checked="selected=='other'" ng-true-value="'other'" ng-model="selected">Other
  </div>
</body>
</html>

Mahesh
fuente
0

Si alguien necesita una solución sin bibliotecas externas de JavaScript, puede usar este ejemplo. Un grupo de casillas de verificación que permiten valores 0..1. Puede hacer clic en el componente de casilla de verificación o el texto de la etiqueta asociada.

    <input id="mygroup1" name="mygroup" type="checkbox" value="1" onclick="toggleRadioCheckbox(this)" /> <label for="mygroup1">Yes</label>
    <input id="mygroup0" name="mygroup" type="checkbox" value="0" onclick="toggleRadioCheckbox(this)" /> <label for="mygroup0">No</label>

- - - - - - - - 

    function toggleRadioCheckbox(sender) {
        // RadioCheckbox: 0..1 enabled in a group 
        if (!sender.checked) return;
        var fields = document.getElementsByName(sender.name);
        for(var idx=0; idx<fields.length; idx++) {
            var field = fields[idx];
            if (field.checked && field!=sender)
                field.checked=false;
        }
    }
Quien
fuente
0

Mi versión: uso de atributos de datos y JavaScript de Vanilla

<div class="test-checkbox">
    Group One: <label>
        <input type="checkbox" data-limit="only-one-in-a-group" name="groupOne" value="Eat" />Eat</label>
    <label>
        <input type="checkbox" data-limit="only-one-in-a-group" name="groupOne" value="Sleep" />Sleep</label>
    <label>
        <input type="checkbox" data-limit="only-one-in-a-group" name="groupOne" value="Play" />Play</label>
    <br />
    Group Two: <label>
        <input type="checkbox" data-limit="only-one-in-a-group" name="groupTwo" value="Fat" />Fat</label>
    <label>
        <input type="checkbox" data-limit="only-one-in-a-group" name="groupTwo" value="Comfort" />Comfort</label>
    <label>
        <input type="checkbox" data-limit="only-one-in-a-group" name="groupTwo" value="Happy" />Happy</label>
</div>
<script>
    let cbxes = document.querySelectorAll('input[type="checkbox"][data-limit="only-one-in-a-group"]');
    [...cbxes].forEach((cbx) => {
        cbx.addEventListener('change', (e) => {
            if (e.target.checked)
                uncheckOthers(e.target);
        });
    });
    function uncheckOthers (clicked) {
        let name = clicked.getAttribute('name');
        // find others in same group, uncheck them
        [...cbxes].forEach((other) => {
            if (other != clicked && other.getAttribute('name') == name)
                other.checked = false;
        });
    }
</script>
benbai123
fuente
-1

Nigromancia:
y sin jQuery, para una estructura de casilla de verificación como esta:

<label>
<input type="checkbox" id="mytrackers_1" name="blubb_1" value="">--- Bitte ausw&#228;hlen ---
</label>
<label>
<input type="checkbox" id="mytrackers_2" name="blubb_2" value="7">Testtracker
</label>
<label>
<input type="checkbox" id="mytrackers_3" name="blubb_3" value="3">Kundenanfrage
</label>
<label>
<input type="checkbox" id="mytrackers_4" name="blubb_4" value="2">Anpassung
</label>
<label>
<input type="checkbox" id="mytrackers_5" name="blubb_5" value="1" checked="checked" >Fehler
</label>
<label>
<input type="checkbox" id="mytrackers_6" name="blubb_6" value="4">Bedienung
</label>
<label>
<input type="checkbox" id="mytrackers_7" name="blubb_7" value="5">Internes
</label>
<label>
<input type="checkbox" id="mytrackers_8" name="blubb_8" value="6">&#196;nderungswunsch
</label>

lo harías así:

    /// attach an event handler, now or in the future, 
    /// for all elements which match childselector,
    /// within the child tree of the element maching parentSelector.
    function subscribeEvent(parentSelector, eventName, childSelector, eventCallback) {
        if (parentSelector == null)
            throw new ReferenceError("Parameter parentSelector is NULL");
        if (childSelector == null)
            throw new ReferenceError("Parameter childSelector is NULL");
        // nodeToObserve: the node that will be observed for mutations
        var nodeToObserve = parentSelector;
        if (typeof (parentSelector) === 'string')
            nodeToObserve = document.querySelector(parentSelector);
        var eligibleChildren = nodeToObserve.querySelectorAll(childSelector);
        for (var i = 0; i < eligibleChildren.length; ++i) {
            eligibleChildren[i].addEventListener(eventName, eventCallback, false);
        } // Next i 
        // /programming/2712136/how-do-i-make-this-loop-all-children-recursively
        function allDescendants(node) {
            if (node == null)
                return;
            for (var i = 0; i < node.childNodes.length; i++) {
                var child = node.childNodes[i];
                allDescendants(child);
            } // Next i 
            // IE 11 Polyfill 
            if (!Element.prototype.matches)
                Element.prototype.matches = Element.prototype.msMatchesSelector;
            if (node.matches) {
                if (node.matches(childSelector)) {
                    // console.log("match");
                    node.addEventListener(eventName, eventCallback, false);
                } // End if ((<Element>node).matches(childSelector))
                // else console.log("no match");
            } // End if ((<Element>node).matches) 
            // else console.log("no matchfunction");
        } // End Function allDescendants 
        // Callback function to execute when mutations are observed
        var callback = function (mutationsList, observer) {
            for (var _i = 0, mutationsList_1 = mutationsList; _i < mutationsList_1.length; _i++) {
                var mutation = mutationsList_1[_i];
                // console.log("mutation.type", mutation.type);
                // console.log("mutation", mutation);
                if (mutation.type == 'childList') {
                    for (var i = 0; i < mutation.addedNodes.length; ++i) {
                        var thisNode = mutation.addedNodes[i];
                        allDescendants(thisNode);
                    } // Next i 
                } // End if (mutation.type == 'childList') 
                // else if (mutation.type == 'attributes') { console.log('The ' + mutation.attributeName + ' attribute was modified.');
            } // Next mutation 
        }; // End Function callback 
        // Options for the observer (which mutations to observe)
        var config = { attributes: false, childList: true, subtree: true };
        // Create an observer instance linked to the callback function
        var observer = new MutationObserver(callback);
        // Start observing the target node for configured mutations
        observer.observe(nodeToObserve, config);
    } // End Function subscribeEvent 


    function radioCheckbox_onClick() 
    { 
        // console.log("click", this);
        let box = this;
        if (box.checked) 
        {
            let name = box.getAttribute("name");
            let pos = name.lastIndexOf("_");
            if (pos !== -1) name = name.substr(0, pos);

            let group = 'input[type="checkbox"][name^="' + name + '"]';
            // console.log(group);
            let eles = document.querySelectorAll(group);
            // console.log(eles);
            for (let j = 0; j < eles.length; ++j) 
            {
                eles[j].checked = false;
            }
            box.checked = true;
        }
        else
            box.checked = false;
    }


    // /programming/9709209/html-select-only-one-checkbox-in-a-group
    function radioCheckbox()
    { 
        // on instead of document...
        let elements = document.querySelectorAll('input[type="checkbox"]')

        for (let i = 0; i < elements.length; ++i)
        {
            // console.log(elements[i]);
            elements[i].addEventListener("click", radioCheckbox_onClick, false);

        } // Next i 

    } // End Function radioCheckbox 


    function onDomReady()
    {
        console.log("dom ready");
        subscribeEvent(document, "click", 
            'input[type="checkbox"]', 
            radioCheckbox_onClick
        ); 

        // radioCheckbox();
    }

    if (document.addEventListener) document.addEventListener("DOMContentLoaded", onDomReady, false);
    else if (document.attachEvent) document.attachEvent("onreadystatechange", onDomReady);
    else window.onload = onDomReady;

    function onPageLoaded() {
        console.log("page loaded");
    }

    if (window.addEventListener) window.addEventListener("load", onPageLoaded, false);
    else if (window.attachEvent) window.attachEvent("onload", onPageLoaded);
    else window.onload = onPageLoaded;
Stefan Steiger
fuente
-1
//Here is a solution using JQuery    
<input type = "checkbox" class="a"/>one
    <input type = "checkbox" class="a"/>two
    <input type = "checkbox" class="a"/>three
    <script>
       $('.a').on('change', function() {
            $('.a').not(this).prop('checked',false);
    });
    </script>
Tabish Zaman
fuente