¿Por qué el evento jquery change no se activa cuando configuro el valor de una selección usando val ()?

377

La lógica en el change()controlador de eventos no se ejecuta cuando se establece el valor val(), pero se ejecuta cuando el usuario selecciona un valor con el mouse. ¿Por qué es esto?

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

Respuestas:

589

Porque el changeevento requiere un evento de navegador real iniciado por el usuario en lugar de a través del código javascript.

Haz esto en su lugar:

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

o

$("#single").val("Single2").change();
usuario113716
fuente
1
Hola, haciendo esta actualización desplegable. pero ser llamado onChange () recursivamente.
Pankaj
3
Cavo esta respuesta. Funciona, pero ¿no hay una mejor manera con jQuery? Estoy seguro de que TODOS recordaremos hacer esto cada vez que cambiemos un valor que tenga configurado un controlador de cambio (sarcasmo). ¿Los marcos que usan enlace de datos podrían resolver esto mejor?
Jess
@ user113716 ¿sabrías cómo activarlo sin conocer ningún valor?
BKSpurgeon
44
Estoy de acuerdo en que esta es la respuesta correcta, pero esto es una mierda y arruina lo que estoy tratando de hacer.
Dustin Poissant
Pruebe $ ("# single"). Trigger ({type: "change", val: "Single2"})
user2901633
44

Creo que puede activar manualmente el evento de cambio con trigger():

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

Aunque no sé por qué no se dispara automáticamente.

David dice que reinstale a Mónica
fuente
No puedo hacer que esto funcione, también $ ("# single"). Val ("Single2"). Change (); Estoy creando dinámicamente un menú desplegable y cambiando su valor (Funciona bien para mí) Pero cuando intento activar el cambio, no funciona para mí.
Maneesh Kumar
44
Un "bit" tardío pero no se dispara automáticamente porque conduciría a bucles infinitos. Piensa$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ
@Juhana Creo que un bucle infinito es mucho más fácil de notar, diagnosticar y corregir que val () misteriosamente no puede activar enlaces de "cambio".
iono
Llamar a .change () es una abreviatura para llamar a .trigger ('change').
Triynko
9

Agregar este fragmento de código después de val () parece funcionar:

$(":input#single").trigger('change');
Eric Belair
fuente
66
Sí, pero no necesita hacer una selección DOM separada para ello $(":input#single"). De hecho, realmente no deberías. Solo encadenarlo después del .val(). Puedes usar .trigger('change')o .change(). Son exactamente lo mismo.
user113716
8

Por lo que puedo leer en las API. El evento solo se activa cuando el usuario hace clic en una opción.

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

Para cuadros de selección, casillas de verificación y botones de opción, el evento se activa inmediatamente cuando el usuario realiza una selección con el mouse, pero para los otros tipos de elementos, el evento se difiere hasta que el elemento pierde el foco.

Marnix
fuente
¿Cuáles son las alternativas para los otros tipos de elementos? Quiero que el evento 'cambio' se active inmediatamente para los inputelementos, no cuando el elemento pierde el foco. ¿Tú sabes?
Dan Nissenbaum
1
Si con "inmediatamente" quiere decir "cada vez que se presiona una tecla en la entrada" está buscando los eventos onkeyup, onkeypress y onkeydown, no onchange.
user2867288
6

Para hacerlo más fácil, agregue una función personalizada y llámela cuando quiera que cambiar el valor también active el cambio

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

y

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

O puede anular la función val para llamar siempre al cambio cuando se llama al val

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

Muestra en http://jsfiddle.net/r60bfkub/

Alireza Fattahi
fuente
Mi navegador se queja de demasiada recurrencia, ¿alguna solución para esto?
Bhargav Nanekalva
Está escuchando el changeevento sobre un control y está ejecutando una devolución de llamada que (directa o indirectamente) activa nuevamente el changeevento sobre el mismo control. Le sugiero que use otro nombre para el evento que activa manualmente (por ejemplo explicit.change), para que no vuelva a activar el changeevento, evite el bucle y aún le permita reaccionar ante el evento.
Kamafeather
3

En caso de que no desee mezclarse con el evento de cambio predeterminado, puede proporcionar su evento personalizado

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

para activar el evento en el conjunto de valores, puede hacer

$('input.test').val('I am a new value').trigger('value_changed');
ritmo de codificación
fuente
3

Me encontré con el mismo problema mientras usaba CMB2 con Wordpress y quería conectarme al evento de cambio de un metabox de carga de archivos.

Entonces, en caso de que no pueda modificar el código que invoca el cambio (en este caso, el script CMB2), use el código a continuación. El desencadenante se invoca DESPUÉS de que se establece el valor; de lo contrario, su event event de cambio funcionará, pero el valor será el anterior, no el establecido.

Aquí está el código que 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);
usuario2075039
fuente
Esto es bueno, pero ¿puede mostrar cómo lo limitaría a una sola entrada en particular?
jwebb
@jwebb ¿No estás seguro de lo que quieres decir? Estamos anulando la función jQuery val (). Vincula un controlador de eventos de cambio a una entrada específica.
user2075039
Quiero decir, @ user2075039, ¿qué pasa si hay varias entradas en la página que utilizan la función jQuery val () y no desea vincular el controlador de eventos de cambio personalizado a TODOS ellos sino solo a uno de ellos?
jwebb
@jwebb puede verificar this.selectordentro de la $.fn.valfunción de anulación , para un selector específico (dependerá de lo que se use para el selector). Este es el mejor que he encontrado para hacer esto sólo para campos específicos, el único problema es que usted debe saber lo que están utilizando para el selector
Smyles
1
$(":input#single").trigger('change');

Esto funcionó para mi guión. Tengo 3 combos y enlaces con el evento chainSelect, necesito pasar 3 valores por url y por defecto seleccionar todo desplegable. Yo usé esto

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

Y el primer evento funcionó.

Prashant Patil
fuente
10
Espero que nunca hagas esto en el mundo real. No hace falta decir que no se puede confiar en $ _GET ['lo que sea'].
Denis V
1

Si acaba de agregar la opción de selección a un formulario y desea activar el evento de cambio, he encontrado que se requiere setTimeout; de lo contrario, jQuery no selecciona el cuadro de selección recién agregado:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
Dave Hilditch
fuente