Moduł obsługi zdarzeń OnChange dla przycisku opcji (typ INPUT = „radio”) nie działa jako jedna wartość

190

Szukam uogólnionego rozwiązania tego problemu.

Rozważ 2 wejścia radiowe o tej samej nazwie. Po przesłaniu sprawdzany określa wartość wysyłaną z formularzem:

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

Zdarzenie zmiany nie jest uruchamiane, gdy przycisk opcji jest wyłączony. Jeśli więc radio o wartości = „1” jest już wybrane, a użytkownik wybierze drugie, uchwytChange1 () nie działa. To stanowi problem (dla mnie zresztą) polegający na tym, że nie ma zdarzenia, w którym mógłbym złapać to usunięcie zaznaczenia.

To, co chciałbym, to obejście zdarzenia onchange dla wartości grupy pól wyboru lub alternatywnie zdarzenie oncheck, które wykrywa nie tylko, gdy radio jest zaznaczone, ale także, gdy nie jest zaznaczone.

Jestem pewien, że niektórzy z was wcześniej napotkali ten problem. Jakie są obejścia (lub idealnie, jak to zrobić)? Chcę tylko złapać zdarzenie zmiany, uzyskać dostęp do wcześniej sprawdzonego radia, a także nowo sprawdzonego radia.

PS
onclick wydaje się lepszym zdarzeniem (przeglądarkowym) do wskazania, kiedy radio jest sprawdzane, ale nadal nie rozwiązuje problemu niezaznaczonego.

Podejrzewam, że ma sens, dlaczego onchange dla typu pola wyboru działa w takim przypadku, ponieważ zmienia wartość, którą przesyła, gdy go zaznaczasz lub odznaczasz. Chciałbym, żeby przyciski radiowe zachowywały się bardziej jak wymiana elementu SELECT, ale co możesz zrobić ...

Mateusz
źródło

Odpowiedzi:

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>

Oto demo JSFiddle: https://jsfiddle.net/crp6em1z/

Michał
źródło
4
Tylko uwaga, dlaczego wybrałem to jako prawidłową odpowiedź: Procedury obsługi zdarzeń kliknięcia są ustawione na każdym przycisku opcji z atrybutem name, myRadiosaby odczytać zmienną, prevktóra zawiera aktualnie wybrane radio. W ramach każdej procedury obsługi kliknięć dokonuje się porównania, aby zdecydować, czy kliknięte radio jest takie samo, jak zapisane w prevradiu, a jeśli nie, wówczas przechowywane w nim radio jest przechowywane. W module obsługi kliknięć masz dostęp do poprzednio wybranego: previ aktualnie wybranego radia:this
Matthew
26
Lepiej byłoby buforować funkcję poza pętlą, aby wszystkie radia miały tę samą procedurę obsługi zdarzeń (teraz mają identyczne procedury obsługi, ale są różnymi funkcjami). A może włóż wszystkie radia do opakowania i skorzystaj z funkcji delegowania wydarzeń
Oriol,
1
@Oriol lub ktoś znający się na rzeczy, czy możesz podać przykład (1) buforowania poza pętlą lub (2) otoki + delegowanie zdarzeń?
Matt Voda
14
onclick nie działa z wyborem klawiatury, można go używać rad[i].addEventListener('change', function(){ //your handler code })i będzie działał zarówno na myszy, jak i na klawiaturze
Juanmi Rodriguez
117

Dokonałbym dwóch zmian:

<input type="radio" name="myRadios" onclick="handleClick(this);" value="1" />
<input type="radio" name="myRadios" onclick="handleClick(this);" value="2" />
  1. onclickZamiast tego użyj procedury obsługi onchange- zmieniasz „stan zaznaczony” wejścia radiowego, a nie value, więc nie dzieje się żadne zdarzenie zmiany.
  2. Użyj jednej funkcji i przekaż thisjako parametr, który ułatwi sprawdzenie, która wartość jest aktualnie wybrana.

ETA: Wraz z handleClick()funkcją możesz śledzić oryginalną / starą wartość radia w zmiennej o zasięgu strony. To jest:

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" />

Nate Cook
źródło
Dzięki, chociaż to nie rozwiązuje problemu konieczności pobrania poprzednio sprawdzonego radia, a ty również mówisz coś, o czym wspominali inni użytkownicy, a mianowicie użycie „onclick” zamiast „onchange”. Właściwie to wiedziałem od samego początku, ale chciałem zwrócić uwagę na fakt, że onchange nie działa tak, jak można się spodziewać, i chciałbym sobie z tym poradzić lepiej.
Matthew
1
Używasz JavaScript, prawda? Dlaczego więc nie zachować zmiennej, która przechowuje ostatni znany wybrany przycisk opcji? Jeśli używasz jednego modułu obsługi, możesz sprawdzić tę przechowywaną wartość, zanim zastąpisz ją nową wartością. +1
jmort253
13
@Matthew: Program onclickobsługi został po prostu źle nazwany - obsługuje zdarzenie wyboru przycisku radiowego, niezależnie od tego, czy przycisk zostanie kliknięty, dotknięty, czy aktywowany poprzez naciśnięcie klawisza „enter” na klawiaturze. Procedura onchangeobsługi nie jest w tym przypadku odpowiednia, ponieważ wartość danych wejściowych się nie zmienia, tylko atrybut zaznaczony / niezaznaczony. Dodałem przykładowy skrypt, aby rozwiązać poprzednią wartość.
Nate Cook
1
„onClick” nie obsłuży zdarzenia, jeśli użytkownik użyje klawiatury (tab + spacja), aby wybrać radio (i jest to powszechna praktyka w przypadku dużych formularzy).
HoldOffHunger
+1. „onChange ()” nie jest zdarzeniem ogniowym w ReactJS i jest to jedyne rozwiązanie. Źródło: github.com/facebook/react/issues/1471
HoldOffHunger
42

Jak widać z tego przykładu: 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);
});

zarówno zdarzenia, jak clicki changezdarzenia są uruchamiane po wybraniu opcji przycisku opcji (przynajmniej w niektórych przeglądarkach).

Powinienem również zauważyć, że w moim przykładzie clickzdarzenie jest nadal uruchamiane, gdy używasz klawisza tab i klawiatury, aby wybrać opcję.

Chodzi mi o to, że chociaż changezdarzenie jest uruchamiane w niektórych przeglądarkach, clickpowinno ono zapewniać wymagany zasięg.

Philip Walton
źródło
6
Tak, ponieważ console.logw moim kodzie znajduje się instrukcja, której IE7 nie obsługuje. Możesz po prostu zaalarmować w IE, jeśli chcesz.
Philip Walton,
Dzięki. Nie dotyczy to jednak sposobu uzyskania wcześniej zaznaczonego pola wyboru. Również dzięki, nie wiedziałem, że console.log nie działa w IE.
Matthew
Nie podwajaj programów obsługi zdarzeń - w przeglądarkach, które odpalają zarówno program obsługi zdarzeń, jak clicki changeprocedury obsługi zdarzeń, dwukrotnie wywołujesz procedurę obsługi zdarzeń. W tym przypadku, ponieważ @Matthew dotyczy poprzedniej wartości, może to prowadzić do złych konsekwencji.
Nate Cook
3
@NateCook wyraźnie nie trafiłeś w sedno mojego przykładu. Pokazałem, że za każdym razem, gdy uruchamiane jest zdarzenie zmiany, uruchamiane jest również zdarzenie kliknięcia. To, że użyłem obu wydarzeń w moim przykładzie, nie oznacza, że ​​je promowałem. Myślę, że twoje głosowanie w dół było niezasłużone.
Philip Walton
Ale promowałeś go - twoja pierwotna odpowiedź brzmiała: „Mam na myśli to, że chociaż zdarzenie zmiany jest uruchamiane w niektórych przeglądarkach, zdarzenie kliknięcia powinno zapewniać zasięg, którego potrzebujesz jako rezerwowy, i możesz użyć zmiany w przeglądarkach które to obsługują ”. clickjest tu poprawnym przewodnikiem i jedynym, którego potrzebujesz. Twoja poprawka wyjaśnia to, dlatego usuwam mój głos negatywny.
Nate Cook
10

Co powiesz na użycie zdarzenia zmiany 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/

Razan Paul
źródło
$(this).val()można również zastąpić rodzimym javascript e.currentTarget.value, gdzie e jest obiektem zdarzenia przekazywanym przez funkcję wywołania zwrotnego.
Eric
6

Jak widać tutaj: http://www.w3schools.com/jsref/event_onchange.asp Atrybut onchange nie jest obsługiwany dla przycisków opcji.

Pierwsze połączone przez Ciebie pytanie SO daje odpowiedź: użyj onclickzdarzenia i sprawdź stan przycisku opcji w funkcji, którą uruchamia.

Constantin Groß
źródło
To tylko trochę niekompletne. Więc po utworzeniu funkcji do obsługi wszystkich kliknięć w grupie, jak sprawdzisz, aby sprawdzić, która została usunięta? Ponadto szukam rozwiązania nie wymagającego kwerendy.
Matthew
Kliknięty przycisk opcji zostanie zaznaczony, wszystkie pozostałe w tej samej grupie zostaną odznaczone. Lub możesz przejrzeć wszystkie przyciski opcji w tej grupie i sprawdzić ich status. Jeśli podałeś więcej informacji o tym, co chcesz zrobić za pomocą przycisków opcji, łatwiej byłoby ci powiedzieć, jak to zrobić.
Constantin Groß
2
onclicknie jest tym samym semantycznym, ponieważ można zmienić sprawdzanie przycisku opcji poprzez wprowadzanie danych z klawiatury przy włączonym wyborze formy klawiatury.
gsnedders
Wydaje się jednak, że @gsnedders onclick działa za pomocą klawiatury w większości przeglądarek - Firefox, IE, Safari, Chrome. Dziwne, że robi to, co powinien robić onchange, ale robi. Jestem jednak ciekawy, jak to działa na platformach mobilnych.
Matthew
1
w3schools dla 1 i nie rozwiązał całego problemu dla 2, czyli sposobu uzyskania wcześniej wybranego radia. 2 było najważniejszą częścią pytania w mojej głowie.
Matthew
6

Nie sądzę, że istnieje inny sposób niż przechowywanie poprzedniego stanu. Oto rozwiązanie z 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" />

Po głębszym przemyśleniu postanowiłem pozbyć się zmiennej i dodać / usunąć klasę. Oto, co dostałem: http://jsfiddle.net/BeQh3/2/

Alex Okrushko
źródło
1
Myślałem o użyciu jQuery i jest zdecydowanie więcej, co można by z tym zrobić. Możesz powiązać niektóre zdarzenia niestandardowe dla zaznaczonych i niezaznaczonych, a nawet sprawdzić dziwactwa w różnych przeglądarkach. Brzmi jak dobry pomysł na wtyczkę.
Matthew
Dzięki. Lubię jQuery, ale w tym przypadku jest on dla mnie niedostępny.
Matthew
W jaki sposób jQuery jest dla ciebie niedostępny?
jmort253
1
Gdyby jQuery było dla mnie niedostępne, znalazłbym inną pracę.
Adrian Carr
5

Tak, nie ma zdarzenia zmiany dla aktualnie wybranego przycisku opcji. Problem polega jednak na tym, że każdy przycisk opcji jest traktowany jako osobny element. Zamiast tego grupa radiowa powinna być uważana za pojedynczy element, taki jak select. Tak więc dla tej grupy uruchamiane jest zdarzenie zmiany. Jeśli jest to selectelement, nigdy nie martwimy się o każdą z zawartych w nim opcji, ale bierzemy tylko wybraną opcję. Przechowujemy bieżącą wartość w zmiennej, która stanie się poprzednią wartością, gdy zostanie wybrana nowa opcja. Podobnie musisz użyć oddzielnej zmiennej do przechowywania wartości zaznaczonego przycisku opcji.

Jeśli chcesz zidentyfikować poprzedni przycisk opcji, musisz zapętlić mousedownzdarzenie.

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

zobacz to: http://jsfiddle.net/diode/tywx6/2/

Dioda
źródło
Pomyślałem o użyciu mousedown do sprawdzenia przed kliknięciem, ale to nie zadziała, gdy użyjesz spacji do wyboru radia. Może wydarzenie skupiające się na miejscu lub w uzupełnieniu tego, o czym wspomniałeś.
Matthew
5

Przechowuj poprzednio sprawdzone radio w zmiennej:
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);

JS PRZYKŁADOWY KOD

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);
Dimitar Bonev
źródło
Dzięki. Mogę posunąć skrzypce jeszcze bardziej i schować radio. W ten sposób, gdy wartość się zmienia, masz odniesienie do wcześniej wybranego radia, a nie tylko jego wartości.
Matthew
@Matthew Właściwie to skrzypce, które udostępniłem, zawierało element radiowy, a nie tylko wartość. Wartość została zarejestrowana, aby pokazać przeznaczenie kodu, ale nie została zapisana do późniejszego użycia. Edytuję nazwy zmiennych, aby uzyskać więcej wyjaśnień: previousChecked -> previousCheckedRadio, że -> currentCheckedRadio;
Dimitar Bonev
Dzięki. To dobre rozwiązanie, z wyjątkiem użycia zdarzenia zmiany, które nie zachowuje się poprawnie w różnych przeglądarkach. Jeśli zamiast tego użyjesz kliknięcia, byłoby lepiej.
Matthew
5

Zdaję sobie sprawę, że to stary problem, ale ten fragment kodu działa dla mnie. Być może ktoś w przyszłości uzna to za przydatne:

<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>
John K.
źródło
1
Jeśli dodasz, onkeydown="radioChange('juju','button1',radioArray);"możesz także przechwytywać, gdy użytkownik wykorzystuje miejsce do sprawdzenia radia.
Matthew
2

Jest to tuż przy mojej głowie, ale możesz zrobić zdarzenie onClick dla każdego przycisku opcji, nadać im różne identyfikatory, a następnie zrobić pętlę for, aby przejść przez każdy przycisk opcji w grupie i znaleźć, który jest został sprawdzony poprzez sprawdzenie atrybutu „sprawdzone”. Identyfikator sprawdzanego będzie przechowywany jako zmienna, ale możesz najpierw użyć zmiennej tymczasowej, aby upewnić się, że wartość tej zmiennej się zmieni, ponieważ zdarzenie click uruchomi się, niezależnie od tego, czy zaznaczono nowy przycisk opcji.

Andrew Latham
źródło
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>
umesh unnikrishnan
źródło
2

Jeśli chcesz uniknąć wbudowanego skryptu, możesz po prostu słuchać zdarzenia kliknięcia w radiu. Można to osiągnąć za pomocą zwykłego Javascript, słuchając zdarzenia kliknięcia na

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);
      }
}
klaczy
źródło
2

Możesz dodać następujący skrypt 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>
Brzęczeć
źródło
1

to działa dla mnie

<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>
Doberon
źródło
Myślę, że powinna to być odpowiedź teraz, gdy jest obsługiwana.
Leo
0

Jest to najłatwiejsza i najbardziej wydajna funkcja, wystarczy dodać tyle przycisków, ile chcesz do zaznaczonego = false i ustawić zdarzenie onclick dla każdego przycisku opcji. Wyznacz unikalny numer dla każdego przycisku opcji

function AdjustRadios(which) 
{
    if(which==1)
         document.getElementById("rdpPrivate").checked=false;
    else if(which==2)
         document.getElementById("rdbPublic").checked=false;
}
Jama
źródło
0

Najłatwiejsza i pełna moc

tylko do odczytu wejścia radiowe za pomocą 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

ßãlãjî
źródło