Por que o evento jquery change não é acionado quando eu defino o valor de um select usando val ()?

377

A lógica no change()manipulador de eventos não está sendo executada quando o valor é definido por val(), mas é executada quando o usuário seleciona um valor com o mouse. Por que é isso?

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

Respostas:

589

Como o changeevento requer um evento real do navegador iniciado pelo usuário em vez de via código javascript.

Faça isso:

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

ou

$("#single").val("Single2").change();
user113716
fonte
11
Olá, faça esta atualização suspensa. mas sendo chamado onChange () recursivamente.
Pankaj
3
Eu cavo esta resposta. Funciona, mas não existe uma maneira melhor com o jQuery? Tenho certeza de que todos nos lembraremos de fazer isso toda vez que alterarmos um valor que tenha um manipulador de alterações configurado (sarcasmo). Estruturas que usam ligação de dados podem resolver isso melhor?
Jess
@ user113716 você saberia como mexer sem saber nenhum valor?
BKSpurgeon
4
Concordo que esta é a resposta correta, mas isso é absolutamente péssimo e arruina o que estou tentando fazer.
Dustin Poissant
Tente $ ("# single"). Trigger ({type: "change", val: "Single2"})
user2901633
44

Acredito que você pode disparar manualmente o evento de alteração com trigger():

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

Embora por que ele não dispara automaticamente, não faço ideia.

David diz para restabelecer Monica
fonte
Não consigo trabalhar nisso, também $ ("# single"). Val ("Single2"). Change (); Estou criando dinamicamente dropdown e alterando seu valor (está funcionando bem para mim). Mas quando estou tentando acionar alterações, não está funcionando para mim.
precisa saber é o seguinte
4
Um "pouco" tardio, mas não dispara automaticamente porque levaria a loops infinitos. Pense$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ 28/06
@ Juhana Eu acho que um loop infinito é muito mais fácil de perceber, diagnosticar e consertar do que val () misteriosamente falhando em acionar ligações de "alteração".
iono
Ligar para .change () é uma abreviação para chamar .trigger ('change').
Triynko
9

Adicionar este pedaço de código após o val () parece funcionar:

$(":input#single").trigger('change');
Eric Belair
fonte
6
Sim, mas você não precisa fazer uma seleção DOM separada $(":input#single"). Na verdade, você realmente não deveria. Apenas encadeie após o .val(). Você pode usar .trigger('change')ou .change(). Eles são exatamente os mesmos.
precisa saber é o seguinte
8

Tanto quanto eu posso ler nas APIs. O evento é acionado apenas quando o usuário clica em uma opção.

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

Para caixas de seleção, caixas de seleção e botões de opção, o evento é acionado imediatamente quando o usuário faz uma seleção com o mouse, mas para os outros tipos de elemento, o evento é adiado até que o elemento perca o foco.

Marnix
fonte
Quais são as alternativas para os outros tipos de elementos? Quero que o evento 'change' seja acionado imediatamente para inputelementos, não quando o elemento perde o foco. Você sabe?
Dan Nissenbaum
11
Se por "imediatamente" você quer dizer "sempre que uma tecla for pressionada na entrada", você está procurando os eventos onkeyup, onkeypress e onkeydown, não na troca.
user2867288
6

Para facilitar, adicione uma função personalizada e chame-a sempre que desejar que a alteração do valor também acione a alteração

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

e

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

Ou você pode substituir a função val para sempre chamar a alteração quando o val for chamado

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

Exemplo em http://jsfiddle.net/r60bfkub/

Alireza Fattahi
fonte
Meu navegador reclama muito de recursão, alguma correção para isso?
Bhargav Nanekalva
Você está ouvindo o change-event sobre um controle e executando um retorno de chamada que (direta ou indiretamente) dispara novamente o change-event sobre o mesmo controle. Eu sugiro que você use outro nome para o evento que você acionar manualmente (por exemplo explicit.change), para que ele não ative changenovamente o -event, evite o loop e ainda permita que você reaja ao evento.
Kamafeather
3

Caso não queira se misturar com o evento de alteração padrão, você pode fornecer seu evento personalizado

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

para acionar o evento no conjunto de valores, você pode fazer

$('input.test').val('I am a new value').trigger('value_changed');
ritmo de codificação
fonte
3

Corri para o mesmo problema enquanto usava o CMB2 com o Wordpress e queria me conectar ao evento de mudança de uma metabox de upload de arquivo.

Portanto, caso você não consiga modificar o código que chama a alteração (nesse caso, o script CMB2), use o código abaixo. O gatilho está sendo chamado APÓS o valor ser definido, caso contrário, seu eventHandler de alteração funcionará, mas o valor será o anterior, e não o que está sendo definido.

Aqui está o código que eu 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);
user2075039
fonte
Isso é bom, mas você pode mostrar como limitá-lo a apenas uma entrada específica?
jwebb
@jwebb Não sabe ao certo o que você quer dizer? Estamos substituindo a função jQuery val (). Você liga um manipulador de eventos de mudança a uma entrada específica.
user2075039
Quero dizer, @ user2075039, e se houver várias entradas na página usando a função jQuery val () e você não quiser vincular o manipulador de eventos de alteração personalizado a TODOS eles, mas apenas um deles?
jwebb
@jwebb, você pode verificar this.selectordentro da $.fn.valfunção de substituição , um seletor específico (depende do que é usado para o seletor). Este é o melhor que eu encontrei para fazer isso apenas para campos específicos, único problema é que você deve saber o que eles estão usando para o seletor
Smyles
1
$(":input#single").trigger('change');

Isso funcionou para o meu script. Eu tenho 3 combos e vincular com o evento chainSelect, eu preciso passar 3 valores por url e padrão selecionar todos drop-down. Eu usei isso

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

E o primeiro evento funcionou.

Prashant Patil
fonte
10
Espero que você nunca faça isso no mundo real. Escusado será dizer que $ _GET ['tanto faz'] não pode ser confiável.
Denis V
1

Se você acabou de adicionar a opção de seleção a um formulário e deseja acionar o evento de alteração, descobri que um setTimeout é necessário, caso contrário o jQuery não seleciona a caixa de seleção recém-adicionada:

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