Il gestore eventi OnChange per il pulsante di opzione (tipo INPUT = "radio") non funziona come un valore


191

Sto cercando una soluzione generalizzata per questo.

Considera 2 ingressi di tipo radio con lo stesso nome. Quando inviato, quello che viene controllato determina il valore che viene inviato con il modulo:

<input type="radio" name="myRadios" onchange="handleChange1();" value="1" />
<input type="radio" name="myRadios" onchange="handleChange2();" value="2" />

L'evento di modifica non si attiva quando viene deselezionato un pulsante di opzione. Pertanto, se la radio con valore = "1" è già selezionata e l'utente seleziona la seconda, handleChange1 () non funziona. Ciò presenta un problema (per me comunque) in quanto non esiste alcun evento in cui posso rilevare questa deselezione.

Quello che vorrei è una soluzione alternativa per l'evento onchange per il valore del gruppo checkbox o in alternativa un evento oncheck che rileva non solo quando una radio è selezionata ma anche quando è deselezionata.

Sono sicuro che alcuni di voi hanno già riscontrato questo problema. Quali sono alcune soluzioni alternative (o idealmente qual è il modo giusto per gestirlo)? Voglio solo vedere l'evento di modifica, accedere alla radio precedentemente verificata e alla radio appena controllata.

PS
onclick sembra un evento migliore (cross-browser) per indicare quando viene controllata una radio ma non risolve ancora il problema non verificato.

Suppongo abbia senso il motivo per cui onchange per un tipo di casella di controllo funziona in un caso come questo poiché modifica il valore che invia quando lo selezioni o deselezioni. Vorrei che i pulsanti di opzione si comportassero più come lo scambio di un elemento SELECT, ma cosa puoi fare ...

Risposte:


179

var rad = document.myForm.myRadios;
var prev = null;
for (var i = 0; i < rad.length; i++) {
    rad[i].addEventListener('change', function() {
        (prev) ? console.log(prev.value): null;
        if (this !== prev) {
            prev = this;
        }
        console.log(this.value)
    });
}
<form name="myForm">
  <input type="radio" name="myRadios"  value="1" />
  <input type="radio" name="myRadios"  value="2" />
</form>

Ecco una demo di JSFiddle: https://jsfiddle.net/crp6em1z/


4
Solo una nota sul perché ho scelto questa come risposta corretta: i gestori di eventi Click sono impostati su ciascuno dei pulsanti di opzione con l'attributo name myRadiosper leggere la variabile prevche contiene la radio attualmente selezionata. Viene eseguito un confronto all'interno di ciascun gestore di clic per decidere se la radio cliccata è la stessa di quella memorizzata preve, in caso contrario, la radio attualmente selezionata viene memorizzata lì. All'interno del gestore di clic, hai accesso al precedentemente selezionato: preve alla radio attualmente selezionata:this
Matthew,

26
Sarebbe meglio memorizzare nella cache la funzione al di fuori del ciclo, in modo che tutte le radio condividano lo stesso gestore di eventi (ora hanno gestori identici ma sono funzioni diverse). O forse metti tutte le radio in un wrapper e usa la delega degli eventi
Oriol

1
@Oriol, o chiunque altro, potresti dare un esempio di (1) memorizzazione nella cache al di fuori del ciclo o (2) wrapper + delega di eventi?
Matt Voda,


14
onclick non funziona con la selezione della tastiera, puoi usarla rad[i].addEventListener('change', function(){ //your handler code })e funzionerà sia per mouse che per tastiera
Juanmi Rodriguez,

117

Vorrei fare due modifiche:

<input type="radio" name="myRadios" onclick="handleClick(this);" value="1" />
<input type="radio" name="myRadios" onclick="handleClick(this);" value="2" />
  1. Usa il onclickgestore invece di onchange: stai cambiando lo "stato controllato" dell'ingresso radio, non quello value, quindi non si sta verificando un evento di modifica.
  2. Utilizzare una singola funzione e passare thiscome parametro per semplificare il controllo del valore attualmente selezionato.

ETA: insieme alla tua handleClick()funzione, puoi tenere traccia del valore originale / vecchio della radio in una variabile con ambito pagina. Questo è:

var currentValue = 0;
function handleClick(myRadio) {
    alert('Old value: ' + currentValue);
    alert('New value: ' + myRadio.value);
    currentValue = myRadio.value;
}

var currentValue = 0;
function handleClick(myRadio) {
    alert('Old value: ' + currentValue);
    alert('New value: ' + myRadio.value);
    currentValue = myRadio.value;
}
<input type="radio" name="myRadios" onclick="handleClick(this);" value="1" />
<input type="radio" name="myRadios" onclick="handleClick(this);" value="2" />


Grazie, anche se questo non affronta il problema di dover ottenere la radio verificata precedente e stai anche affermando qualcosa che altri utenti hanno già menzionato che è usare "onclick" invece di "onchange". In realtà lo sapevo dall'inizio, ma volevo attirare l'attenzione sul fatto che onchange non funziona come ci si potrebbe aspettare e vorrei gestirlo meglio.
Matthew

1
Stai usando JavaScript, vero? Quindi perché non mantenere semplicemente una variabile che memorizza l'ultimo pulsante di opzione selezionato noto? Se si utilizza un singolo gestore, è possibile verificare questo valore memorizzato prima di sovrascriverlo con il nuovo valore. +1
jmort253

13
@Matthew: il onclickgestore è appena chiamato male - gestisce l'evento di selezione del pulsante di opzione se il pulsante viene cliccato, toccato o attivato premendo "invio" su una tastiera. Il onchangegestore non è appropriato in questo caso poiché il valore dell'input non cambia, ma solo l'attributo controllato / deselezionato. Ho aggiunto uno script di esempio per indirizzare il valore precedente.
Nate Cook,

1
"onClick" non gestirà l'evento se l'utente ha utilizzato la tastiera (tab + barra spaziatrice) per selezionare la radio (e questa è una pratica comune su moduli di grandi dimensioni).
HoldOffHunger,

+1. "onChange ()" non è un evento attivabile in ReactJS e questa è l'unica soluzione. Fonte: github.com/facebook/react/issues/1471
HoldOffHunger

42

Come puoi vedere da questo esempio: http://jsfiddle.net/UTwGS/

HTML:

<label><input type="radio" value="1" name="my-radio">Radio One</label>
<label><input type="radio" value="2" name="my-radio">Radio One</label>

jQuery:

$('input[type="radio"]').on('click change', function(e) {
    console.log(e.type);
});

entrambi gli eventi clicke changevengono attivati ​​quando si seleziona un'opzione del pulsante di opzione (almeno in alcuni browser).

Vorrei anche sottolineare che nel mio esempio l' clickevento viene ancora generato quando si utilizza la scheda e la tastiera per selezionare un'opzione.

Quindi, il mio punto è che anche se l' changeevento viene generato da alcuni browser, l' clickevento dovrebbe fornire la copertura di cui hai bisogno.


6
Sì, perché console.lognel mio codice è presente un'istruzione che IE7 non supporta. Potresti semplicemente avvisarlo in IE se lo desideri.
Philip Walton,

Grazie. Questo non spiega come ottenere la casella di controllo precedentemente selezionata. Inoltre, non sapevo che console.log non funzionasse in IE.
Matthew

Non raddoppiare su gestori di eventi - nei browser che il fuoco sia l' clicke changegestori di eventi, ci si ritroverà per chiamare il gestore due volte. In questo caso, poiché @Matthew si occupa del valore precedente, ciò potrebbe portare a conseguenze negative.
Nate Cook,

3
@NateCook hai chiaramente perso il punto del mio esempio. Stavo dimostrando che ogni volta che viene attivato l'evento change, viene attivato anche l'evento click. Solo perché stavo usando entrambi gli eventi nel mio esempio non significa che lo stavo promuovendo. Penso che il tuo voto negativo sia stato immeritato.
Philip Walton,

Ma lo stavi promuovendo - la tua risposta originale diceva "Quindi, il mio punto è che anche se l'evento di modifica è attivato da alcuni browser, l'evento click dovrebbe fornire la copertura di cui hai bisogno come fallback e puoi usare la modifica nei browser che lo supportano ". clickè il gestore corretto qui e l'unico di cui hai bisogno. La tua revisione lo chiarisce, quindi rimuovo il mio voto negativo.
Nate Cook,

10

Che dire dell'utilizzo dell'evento change di Jquery?

$(function() {
    $('input:radio[name="myRadios"]').change(function() {
        if ($(this).val() == '1') {
            alert("You selected the first option and deselected the second one");
        } else {
            alert("You selected the second option and deselected the first one");
        }
    });
});

jsfiddle: http://jsfiddle.net/f8233x20/


$(this).val()può anche essere sostituito con javascript nativo e.currentTarget.value, dove e è l'oggetto evento passato attraverso la funzione di callback.
Eric

6

Come puoi vedere qui: http://www.w3schools.com/jsref/event_onchange.asp L'attributo onchange non è supportato per i pulsanti di opzione.

La prima domanda SO da te collegata ti dà la risposta: usa onclickinvece l' evento e controlla lo stato del pulsante di opzione all'interno della funzione che attiva.


Questo è solo un po 'incompleto. Quindi, dopo aver creato una funzione per gestire tutti i clic nel gruppo, come controlleresti quale è stato deselezionato? Inoltre, sto cercando una soluzione non jquery.
Matteo,

Il pulsante di opzione selezionato verrà selezionato, tutti gli altri membri dello stesso gruppo verranno deselezionati. Oppure, puoi scorrere tutti i pulsanti di opzione di quel gruppo e verificarne lo stato. Se hai fornito ulteriori informazioni su cosa vuoi fare con i pulsanti di opzione, sarebbe più facile dirti come procedere.
Constantin Groß,

2
onclicknon è lo stesso semantico, in quanto è possibile modificare la verifica di un pulsante di opzione tramite l'immissione da tastiera data la selezione del modulo tastiera abilitata.
gsnedders,

@gsnedders onclick sembra funzionare tramite l'input da tastiera nella maggior parte dei browser: Firefox, IE, Safari, Chrome. È strano che faccia quello che dovrebbe fare lo scambio, ma lo fa. Sono curioso di sapere come funziona su piattaforme mobili.
Matteo,

1
w3schools per 1 e non ha risolto l'intero problema per 2 che era come ottenere la radio precedentemente selezionata. 2 era la parte più importante della domanda nella mia mente.
Matthew,

6

Non credo che ci sia altro modo di salvare lo stato precedente. Ecco la soluzione con jQuery

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> 
<script type="text/javascript">
    var lastSelected;
    $(function () {
        //if you have any radio selected by default
        lastSelected = $('[name="myRadios"]:checked').val();
    });
    $(document).on('click', '[name="myRadios"]', function () {
        if (lastSelected != $(this).val() && typeof lastSelected != "undefined") {
            alert("radio box with value " + $('[name="myRadios"][value="' + lastSelected + '"]').val() + " was deselected");
        }
        lastSelected = $(this).val();
    });
</script>

<input type="radio" name="myRadios" value="1" />
<input type="radio" name="myRadios" value="2" />
<input type="radio" name="myRadios" value="3" />
<input type="radio" name="myRadios" value="4" />
<input type="radio" name="myRadios" value="5" />

Dopo averci pensato un po 'di più, ho deciso di sbarazzarmi della variabile e aggiungere / rimuovere la classe. Ecco cosa ho ottenuto: http://jsfiddle.net/BeQh3/2/


1
Ho pensato di usare un jQuery e c'è sicuramente molto altro da fare. È possibile associare alcuni eventi personalizzati per verificare e deselezionare e persino verificare la presenza di stranezze tra browser. Sembra una buona idea per un plugin.
Matthew,

Grazie. Mi piace jQuery ma in questo caso non è disponibile per me.
Matthew,

In che modo jQuery non è disponibile per te?
jmort253,

1
Se jQuery non fosse disponibile per me, troverei un lavoro diverso.
Adrian Carr,

5

Sì, non è presente alcun evento di modifica per il pulsante di opzione attualmente selezionato. Ma il problema è quando ogni pulsante di opzione viene considerato come elemento separato. Invece un gruppo radio dovrebbe essere considerato come un singolo elemento select. Quindi l'evento change viene attivato per quel gruppo. Se è un selectelemento non ci preoccupiamo mai di ogni opzione in esso contenuta, ma prendiamo solo l'opzione selezionata. Memorizziamo il valore corrente in una variabile che diventerà il valore precedente, quando viene selezionata una nuova opzione. Allo stesso modo devi usare una variabile separata per memorizzare il valore del pulsante di opzione selezionato.

Se si desidera identificare il pulsante di opzione precedente, è necessario ripetere l' mousedownevento.

var radios = document.getElementsByName("myRadios");
var val;
for(var i = 0; i < radios.length; i++){
    if(radios[i].checked){
        val = radios[i].value;
    }
}

vedi questo: http://jsfiddle.net/diode/tywx6/2/


Ho pensato di utilizzare mousedown per verificare prima che si verificasse il clic, ma non funzionerà quando si utilizza lo spazio per selezionare la radio. Forse l'evento focus al posto di o in aggiunta a quello che hai menzionato.
Matthew,

5

Memorizza la radio verificata precedente in una variabile:
http://jsfiddle.net/dsbonev/C5S4B/

HTML

<input type="radio" name="myRadios" value="1" /> 1
<input type="radio" name="myRadios" value="2" /> 2
<input type="radio" name="myRadios" value="3" /> 3
<input type="radio" name="myRadios" value="4" /> 4
<input type="radio" name="myRadios" value="5" /> 5

JS

var changeHandler = (function initChangeHandler() {
    var previousCheckedRadio = null;

    var result = function (event) {
        var currentCheckedRadio = event.target;
        var name = currentCheckedRadio.name;

        if (name !== 'myRadios') return;

        //using radio elements previousCheckedRadio and currentCheckedRadio

        //storing radio element for using in future 'change' event handler
        previousCheckedRadio = currentCheckedRadio;
    };

    return result;
})();

document.addEventListener('change', changeHandler, false);

CODICE ESEMPIO JS

var changeHandler = (function initChangeHandler() {
    var previousCheckedRadio = null;

    function logInfo(info) {
        if (!console || !console.log) return;

        console.log(info);
    }

    function logPrevious(element) {
        if (!element) return;

        var message = element.value + ' was unchecked';

        logInfo(message);
    }

    function logCurrent(element) {
        if (!element) return;

        var message = element.value + ' is checked';

        logInfo(message);
    }

    var result = function (event) {
        var currentCheckedRadio = event.target;
        var name = currentCheckedRadio.name;

        if (name !== 'myRadios') return;

        logPrevious(previousCheckedRadio);
        logCurrent(currentCheckedRadio);

        previousCheckedRadio = currentCheckedRadio;
    };

    return result;
})();

document.addEventListener('change', changeHandler, false);

Grazie. Potrei portare il violino ancora un po 'oltre e conservare la radio stessa. In questo modo quando il valore cambia, hai un riferimento alla radio precedentemente selezionata piuttosto che solo il suo valore.
Matteo

@Matthew In realtà il violino che ho condiviso stava memorizzando l'elemento radio e non solo il valore. Il valore è stato registrato per mostrare lo scopo del codice ma non è stato memorizzato per un utilizzo successivo. Sto modificando i nomi delle variabili per diventare più chiari: previousChecked -> previousCheckedRadio, che -> currentCheckedRadio;
Dimitar Bonev,

Grazie. Questa è una buona soluzione fatta eccezione per l'utilizzo dell'evento change che non si comporta correttamente tra i browser. Se hai usato fai clic invece sarebbe meglio.
Matthew,

5

Mi rendo conto che questo è un vecchio problema, ma questo frammento di codice funziona per me. Forse qualcuno in futuro lo troverà utile:

<h2>Testing radio functionality</h2>
<script type="text/javascript">var radioArray=[null];</script>
<input name="juju" value="button1" type="radio" onclick="radioChange('juju','button1',radioArray);" />Button 1
<input name="juju" value="button2" type="radio" onclick="radioChange('juju','button2',radioArray);" />Button 2
<input name="juju" value="button3" type="radio" onclick="radioChange('juju','button3',radioArray);" />Button 3
<br />

<script type="text/javascript">
function radioChange(radioSet,radioButton,radioArray)
  {
  //if(radioArray instanceof Array) {alert('Array Passed');}
  var oldButton=radioArray[0];
  if(radioArray[0] == null)
    {
    alert('Old button was not defined');
    radioArray[0]=radioButton;
    }
  else
    {
    alert('Old button was set to ' + oldButton);
    radioArray[0]=radioButton;
    }
  alert('New button is set to ' + radioArray[0]);
  }
</script>

1
Se aggiungi, onkeydown="radioChange('juju','button1',radioArray);"puoi anche acquisire quando un utente utilizza lo spazio per controllare la radio.
Matteo,

2

Questo è appena fuori dalla mia testa, ma potresti fare un evento onClick per ogni pulsante di opzione, assegnare loro tutti gli ID diversi e quindi fare un ciclo for nell'evento per passare attraverso ciascun pulsante di opzione nel gruppo e trovare quale è è stato verificato osservando l'attributo 'controllato'. L'id di quello selezionato verrebbe memorizzato come variabile, ma potresti voler prima utilizzare una variabile temp per assicurarti che il valore di quella variabile sia cambiato, poiché l'evento click si attiverà indipendentemente dal fatto che sia stato selezionato un nuovo pulsante di opzione.


2
<input type="radio" name="brd" onclick="javascript:brd();" value="IN">   
<input type="radio" name="brd" onclick="javascript:brd();" value="EX">` 
<script type="text/javascript">
  function brd() {alert($('[name="brd"]:checked').val());}
</script>

2

Se vuoi evitare lo script inline, puoi semplicemente ascoltare un evento click alla radio. Ciò può essere ottenuto con Javascript semplice ascoltando un evento click su

for (var radioCounter = 0 ; radioCounter < document.getElementsByName('myRadios').length; radioCounter++) {
      document.getElementsByName('myRadios')[radioCounter].onclick = function() {
        //VALUE OF THE CLICKED RADIO ELEMENT
        console.log('this : ',this.value);
      }
}

2

È possibile aggiungere il seguente script JS

<script>
    function myfunction(event) {
        alert('Checked radio with ID = ' + event.target.id);
    }
    document.querySelectorAll("input[name='gun']").forEach((input) => {
        input.addEventListener('change', myfunction);
    });
</script>

1

questo funziona per me

<input ID="TIPO_INST-0" Name="TIPO_INST" Type="Radio" value="UNAM" onchange="convenio_unam();">UNAM

<script type="text/javascript">
            function convenio_unam(){
                if(this.document.getElementById('TIPO_INST-0').checked){
                    $("#convenio_unam").hide();
                }else{
                    $("#convenio_unam").show(); 
                }                               
            }
</script>

Penso che questa dovrebbe essere la risposta ora che è supportata.
Leo,

0

Questa è la funzione più semplice ed efficiente da usare, basta aggiungere tutti i pulsanti che vuoi a check = false e rendere l'evento onclick di ogni pulsante di opzione chiamare questa funzione. Designare un numero univoco per ciascun pulsante di opzione

function AdjustRadios(which) 
{
    if(which==1)
         document.getElementById("rdpPrivate").checked=false;
    else if(which==2)
         document.getElementById("rdbPublic").checked=false;
}

0

Più semplice e completo

leggere solo ingressi radio usando getAttribute

document.addEventListener('input',(e)=>{

if(e.target.getAttribute('name')=="myRadios")
console.log(e.target.value)
})
<input type="text"  value="iam text" /> 
<input type="radio" name="myRadios" value="1" /> 1
<input type="radio" name="myRadios" value="2" /> 2

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.