Dlaczego zdarzenie zmiany jquery nie jest wyzwalane, gdy ustawiam wartość select za pomocą val ()?

377

Logika w change()module obsługi zdarzeń nie jest uruchamiana, gdy wartość jest ustawiona przez val(), ale działa, gdy użytkownik wybiera wartość za pomocą myszy. Dlaczego to?

<select id="single">
    <option>Single</option>
    <option>Single2</option>
</select>

<script>
    $(function() {
        $(":input#single").change(function() {
           /* Logic here does not execute when val() is used */
        });
    });

    $("#single").val("Single2");
</script>
Eric Belair
źródło

Odpowiedzi:

589

Ponieważ to changezdarzenie wymaga rzeczywistego zdarzenia przeglądarki zainicjowanego przez użytkownika zamiast kodu javascript.

Zrób to zamiast tego:

$("#single").val("Single2").trigger('change');

lub

$("#single").val("Single2").change();
użytkownik113716
źródło
1
Cześć, ta aktualizacja jest rozwijana. ale wywołanie rekurencyjnie onChange ().
Pankaj
3
Kopię tę odpowiedź. Działa, ale czy nie ma lepszego sposobu na jQuery? Jestem pewien, że WSZYSTKO zapamiętamy, aby to zrobić za każdym razem, gdy zmieniamy wartość, która ma skonfigurowany moduł obsługi zmiany (sarkazm). Ramy wykorzystujące powiązanie danych mogą rozwiązać to lepiej?
Jess,
@ user113716 czy wiesz, jak go uruchomić, nie znając żadnych wartości?
BKSpurgeon
4
Zgadzam się, że to poprawna odpowiedź, ale to absolutnie do bani i psuje to, co próbuję zrobić.
Dustin Poissant,
Spróbuj $ („# single”). Trigger ({type: „change”, val: „Single2”}))
user2901633
44

Wierzę, że możesz ręcznie uruchomić zdarzenie zmiany za pomocą trigger():

$("#single").val("Single2").trigger('change');

Choć nie uruchamia się automatycznie, nie mam pojęcia.

David mówi, że przywraca Monikę
źródło
Nie jestem w stanie tego uruchomić, także $ („# single”). Val („Single2”). Change (); Dynamicznie tworzę listę rozwijaną i zmieniam jej wartość (działa dobrze dla mnie) Ale kiedy próbuję uruchomić zmianę, to nie działa dla mnie.
Maneesh Kumar,
4
„Trochę” spóźniony, ale nie strzela automatycznie, ponieważ prowadziłby do nieskończonych pętli. Pomyśl$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ
@Juhana Myślę, że nieskończona pętla jest znacznie łatwiejsza do zauważenia, zdiagnozowania i naprawienia niż val () w tajemniczy sposób nie wyzwalający powiązań „zmiany”.
iono
Wywołanie .change () jest skrótem do wywołania .trigger („zmiana”).
Triynko
9

Wydaje się, że dodanie tego fragmentu kodu po val () działa:

$(":input#single").trigger('change');
Eric Belair
źródło
6
Tak, ale nie musisz robić z nim osobnego wyboru DOM $(":input#single"). W rzeczywistości nie powinieneś. Po prostu połącz go za .val(). Możesz użyć .trigger('change')lub .change(). Są dokładnie takie same.
user113716,
8

O ile mogę przeczytać w API. Zdarzenie jest uruchamiane tylko wtedy, gdy użytkownik kliknie opcję.

http://api.jquery.com/change/

W przypadku pól wyboru, pól wyboru i przycisków opcji zdarzenie jest uruchamiane natychmiast, gdy użytkownik dokonuje wyboru za pomocą myszy, ale w przypadku innych typów elementów zdarzenie jest odraczane do momentu, gdy element straci fokus.

Marnix
źródło
Jakie są alternatywy dla innych typów elementów? Chcę, aby zdarzenie „zmień” było uruchamiane natychmiast dla inputelementów, a nie gdy element traci skupienie. Czy wiesz?
Dan Nissenbaum,
1
Jeśli przez „natychmiast” masz na myśli „za każdym razem, gdy na wejściu zostanie naciśnięty klawisz”, szukasz zdarzeń onkeyup, onkeypress i onkeydown, a nie onchange.
user2867288,
6

Aby ułatwić dodanie niestandardowej funkcji i wywoływanie jej, kiedy tylko chcesz, zmiana wartości powoduje również zmianę

$.fn.valAndTrigger = function (element) {
    return $(this).val(element).trigger('change');
}

i

$("#sample").valAndTirgger("NewValue");

Lub można zastąpić funkcję val, aby zawsze wywoływała zmianę, gdy wywoływana jest val

(function ($) {
    var originalVal = $.fn.val;
    $.fn.val = function (value) {
        this.trigger("change");
        return originalVal.call(this, value);
    };
})(jQuery);

Próbka na http://jsfiddle.net/r60bfkub/

Alireza Fattahi
źródło
Moja przeglądarka skarży się na zbyt dużą rekurencję, jakaś poprawka?
Bhargav Nanekalva
Słuchasz opcji change-event nad kontrolką i wykonujesz wywołanie zwrotne, które (bezpośrednio lub pośrednio) ponownie wyzwala change-event nad tą samą kontrolką. Sugeruję, abyś użył innej nazwy dla zdarzenia, które wyzwalasz ręcznie (np. explicit.change), Aby nie ponownie wyzwalało change-event, zapobiega pętli i nadal pozwala reagować na zdarzenie.
Kamafeather
3

Jeśli nie chcesz mieszać się z domyślnym zdarzeniem zmiany, możesz podać niestandardowe zdarzenie

$('input.test').on('value_changed', function(e){
    console.log('value changed to '+$(this).val());
});

aby wywołać zdarzenie przy ustawionej wartości, możesz to zrobić

$('input.test').val('I am a new value').trigger('value_changed');
rytm kodowania
źródło
3

Napotkałem ten sam problem podczas korzystania z CMB2 z Wordpress i chciałem przyłączyć się do zdarzenia zmiany metaboksu przesyłania plików.

Jeśli więc nie możesz zmodyfikować kodu, który wywołuje zmianę (w tym przypadku skrypt CMB2), użyj poniższego kodu. Wyzwalacz jest wywoływany PO ustawieniu wartości, w przeciwnym razie zmiana zdarzenia eventHandler będzie działać, ale wartość będzie poprzednia, a nie ustawiona.

Oto kod, którego używam:

(function ($) {
    var originalVal = $.fn.val;
    $.fn.val = function (value) {
        if (arguments.length >= 1) {
            // setter invoked, do processing
            return originalVal.call(this, value).trigger('change');
        }
        //getter invoked do processing
        return originalVal.call(this);
    };
})(jQuery);
użytkownik2075039
źródło
To dobrze, ale czy możesz pokazać, w jaki sposób ograniczysz to do jednego konkretnego wkładu?
jwebb
@jwebb Nie do końca wiesz, co masz na myśli? Przesłaniamy funkcję jQuery val (). Powiązanie procedury obsługi zdarzenia zmiany z określonym wejściem.
user2075039,
Mam na myśli, @ user2075039, co zrobić, jeśli na stronie znajduje się wiele danych wejściowych przy użyciu funkcji val () jQuery i nie chcesz powiązać obsługi zdarzeń niestandardowych zmian ze WSZYSTKIMI z nich tylko z jednym?
jwebb
@ jwebb możesz sprawdzić this.selectorwewnątrz $.fn.valfunkcji przesłonięcia dla określonego selektora (będzie to zależało od tego, co jest używane dla selektora). To jest najlepsze, jakie znalazłem do robienia tego tylko dla określonych pól, jedynym problemem jest to, że musisz wiedzieć, czego używają dla selektora
sMyles
1
$(":input#single").trigger('change');

To zadziałało w moim skrypcie. Mam 3 kombinacje i powiązanie ze zdarzeniem chainSelect, muszę przekazać 3 wartości według adresu URL i domyślnie zaznacz wszystkie rozwijane. Użyłem tego

$('#machineMake').val('<?php echo $_GET['headMake']; ?>').trigger('change');

I pierwsze wydarzenie zadziałało.

Prashant Patil
źródło
10
Mam nadzieję, że nigdy nie robisz tego w prawdziwym świecie. Nie trzeba dodawać, że $ _GET [„cokolwiek”] nie można ufać.
Denis V
1

Jeśli właśnie dodałeś opcję select do formularza i chcesz wywołać zdarzenie zmiany, znalazłem, że wymagany jest setTimeout, w przeciwnym razie jQuery nie odbierze nowo dodanego pola wyboru:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
Dave Hilditch
źródło