Perché l'evento change jquery non si attiva quando imposto il valore di una selezione usando val ()?


377

La logica nel change()gestore eventi non viene eseguita quando il valore è impostato da val(), ma viene eseguita quando l'utente seleziona un valore con il mouse. Perchè è questo?

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

Risposte:


589

Perché l' changeevento richiede un evento browser effettivo avviato dall'utente anziché tramite codice javascript.

Fallo invece:

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

o

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

1
Ciao, sto facendo questo aggiornamento a discesa. ma viene chiamato onChange () in modo ricorsivo.
Pankaj,

3
Scavo questa risposta. Funziona, ma non c'è un modo migliore con jQuery? Sono sicuro che TUTTI ricorderemo di farlo ogni volta che cambiamo un valore che ha un gestore di modifica impostato (sarcasmo). I frame che usano l'associazione dei dati potrebbero risolverlo meglio?
Jess,

@utente113716 sapresti come attivarlo senza conoscere alcun valore?
BKSpurgeon,

4
Sono d'accordo che questa è la risposta corretta, ma questo fa assolutamente schifo e rovina ciò che sto cercando di fare.
Dustin Poissant,

Prova $ ("# single"). Trigger ({type: "change", val: "Single2"})
user2901633

44

Credo che tu possa attivare manualmente l'evento di modifica con trigger():

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

Anche se il motivo per cui non si attiva automaticamente, non ne ho idea.


Non riesco a farlo funzionare, anche $ ("# single"). Val ("Single2"). Change (); Sto creando dinamicamente il menu a discesa e cambiando il suo valore (funziona bene per me) Ma quando sto cercando di innescare il cambiamento non funziona per me.
Maneesh Kumar,

4
Un po 'tardivo ma non si attiva automaticamente perché porterebbe a loop infiniti. Pensa$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ,

@Juhana Penso che un loop infinito sia molto più facile da notare, diagnosticare e correggere di val () che misteriosamente non riesce a innescare associazioni di "cambiamento".
iono,

Chiamare .change () è una scorciatoia per chiamare .trigger ('change').
Triynko,

9

L'aggiunta di questo pezzo di codice dopo che val () sembra funzionare:

$(":input#single").trigger('change');

6
Sì, ma non è necessario effettuare una selezione DOM separata con esso $(":input#single"). In realtà non dovresti davvero. Basta incatenarlo dopo il .val(). Puoi usare .trigger('change')o .change(). Sono esattamente gli stessi.
user113716,

8

Per quanto posso leggere nelle API. L'evento viene generato solo quando l'utente fa clic su un'opzione.

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

Per le caselle selezionate, le caselle di controllo e i pulsanti di opzione, l'evento viene generato immediatamente quando l'utente effettua una selezione con il mouse, ma per gli altri tipi di elemento l'evento viene rinviato fino a quando l'elemento non si attiva.


Quali sono le alternative per gli altri tipi di elementi? Voglio che l'evento "change" si attivi immediatamente per gli inputelementi, non quando l'elemento perde lo stato attivo. Lo sai?
Dan Nissenbaum,

1
Se per "immediatamente" intendi "ogni volta che viene premuto un tasto nell'input" stai cercando gli eventi onkeyup, onkeypress e onkeydown, non onchange.
user2867288

6

Per rendere più semplice aggiungere una funzione personalizzata e chiamarla quando si desidera che anche la modifica del valore attivi la modifica

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

e

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

Oppure puoi sovrascrivere la funzione val per chiamare sempre la modifica quando viene chiamata val

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

Esempio su http://jsfiddle.net/r60bfkub/


Il mio browser si lamenta di troppa ricorsione, qualche soluzione per questo?
Bhargav Nanekalva,

State ascoltando il change-event su un controllo ed eseguite un callback che (direttamente o indirettamente) innesca nuovamente il change-event sullo stesso controllo. Ti suggerisco di usare un altro nome per l'evento che attivi manualmente (ad es. explicit.change), In modo che non changeriattivi l' evento, impedisca il loop e ti permetta comunque di reagire all'evento.
Kamafeather,

3

Nel caso in cui non desideri confonderti con un evento di modifica predefinito, puoi fornire il tuo evento personalizzato

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

per attivare l'evento sul set di valori, puoi farlo

$('input.test').val('I am a new value').trigger('value_changed');

3

Ho riscontrato lo stesso problema durante l'utilizzo di CMB2 con Wordpress e volevo collegarmi all'evento di modifica di un metabox di caricamento di file.

Quindi, nel caso in cui non sia possibile modificare il codice che richiama la modifica (in questo caso lo script CMB2), utilizzare il codice seguente. Il trigger viene invocato DOPO che il valore è impostato, altrimenti il ​​tuo evento changeHandler funzionerà, ma il valore sarà quello precedente, non quello impostato.

Ecco il codice che uso:

(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);

Questo va bene, ma puoi mostrare come lo limiteresti a un solo input particolare?
jwebb,

@jwebb Non sei sicuro di cosa intendi? Sostituiamo la funzione jQuery val (). Associare un gestore eventi change a un input specifico.
user2075039

Voglio dire, @ user2075039, cosa succede se ci sono più input nella pagina usando la funzione jQuery val () e non si desidera associare il gestore eventi di modifica personalizzato a TUTTI ma solo uno?
jwebb,

@jwebb è possibile controllare this.selectorall'interno della $.fn.valfunzione di override , per un selettore specifico (dipenderà da ciò che viene utilizzato per il selettore). Questo è il migliore che ho trovato per farlo solo per campi specifici, l'unico problema è che devi sapere cosa stanno usando per il selettore
sMyles

1
$(":input#single").trigger('change');

Questo ha funzionato per la mia sceneggiatura. Ho 3 combo e bind con evento chainSelect, ho bisogno di passare 3 valori per url e di default selezionare tutto il menu a discesa. Ho usato questo

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

E il primo evento ha funzionato.


10
Spero di non farlo mai nel mondo reale. Inutile dire che $ _GET ["qualunque"] non può essere considerato attendibile.
Denis V,

1

Se hai appena aggiunto l'opzione di selezione a un modulo e desideri attivare l'evento di modifica, ho scoperto che è richiesto un setTimeout altrimenti jQuery non seleziona la casella di selezione appena aggiunta:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
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.