Warum wird das Ereignis jquery change nicht ausgelöst, wenn ich den Wert einer Auswahl mit val () festlege?

377

Die Logik im change()Ereignishandler wird nicht ausgeführt, wenn der Wert von festgelegt wird val(), sondern ausgeführt, wenn der Benutzer mit der Maus einen Wert auswählt. Warum ist das?

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

Antworten:

589

Weil das changeEreignis ein tatsächliches Benutzerereignis erfordert, das vom Benutzer anstelle von Javascript-Code initiiert wird.

Tun Sie dies stattdessen:

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

oder

$("#single").val("Single2").change();
user113716
quelle
1
Hallo, mache dieses Update Dropdown. aber rekursiv onChange () aufgerufen werden.
Pankaj
3
Ich grabe diese Antwort. Es funktioniert, aber gibt es keinen besseren Weg mit jQuery? Ich bin sicher, wir werden uns ALLE daran erinnern, dies jedes Mal zu tun, wenn wir einen Wert ändern, für den ein Änderungshandler eingerichtet ist (Sarkasmus). Frameworks, die Datenbindung verwenden, könnten dies besser lösen?
Jess
@ user113716 Würdest du wissen, wie man es auslöst, ohne irgendwelche Werte zu kennen?
BKSpurgeon
4
Ich bin damit einverstanden, dass dies die richtige Antwort ist, aber das ist absolut scheiße und ruiniert, was ich versuche zu tun.
Dustin Poissant
Versuchen Sie $ ("# single"). Trigger ({type: "change", val: "Single2"})
user2901633
44

Ich glaube, Sie können das Änderungsereignis manuell auslösen mit trigger():

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

Obwohl es nicht automatisch ausgelöst wird, habe ich keine Ahnung.

David sagt, Monica wieder einsetzen
quelle
Ich bin nicht in der Lage, daran zu arbeiten, auch $ ("# single"). Val ("Single2"). Change (); Ich erstelle dynamisch Dropdowns und ändere ihren Wert (es funktioniert gut für mich). Aber wenn ich versuche, eine Änderung auszulösen, funktioniert es nicht für mich.
Maneesh Kumar
4
Ein "bisschen" verspätet, aber es wird nicht automatisch ausgelöst, da dies zu Endlosschleifen führen würde. Denken Sie$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ
@Juhana Ich denke, eine Endlosschleife ist viel einfacher zu erkennen, zu diagnostizieren und zu beheben als val (), das auf mysteriöse Weise keine "Änderungs" -Bindungen auslöst.
Iono
Das Aufrufen von .change () ist eine Abkürzung für das Aufrufen von .trigger ('change').
Triynko
9

Das Hinzufügen dieses Codeteils nach val () scheint zu funktionieren:

$(":input#single").trigger('change');
Eric Belair
quelle
6
Ja, aber Sie müssen dafür keine separate DOM-Auswahl treffen $(":input#single"). In der Tat sollten Sie wirklich nicht. Verketten Sie es einfach nach dem .val(). Sie können .trigger('change')oder verwenden .change(). Sie sind genau gleich.
user113716
8

Soweit ich APIs einlesen kann. Das Ereignis wird nur ausgelöst, wenn der Benutzer auf eine Option klickt.

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

Bei Auswahlfeldern, Kontrollkästchen und Optionsfeldern wird das Ereignis sofort ausgelöst, wenn der Benutzer eine Auswahl mit der Maus trifft. Bei den anderen Elementtypen wird das Ereignis jedoch verschoben, bis das Element den Fokus verliert.

Marnix
quelle
Was sind die Alternativen für die anderen Elementtypen? Ich möchte, dass das 'change'-Ereignis sofort für inputElemente ausgelöst wird, nicht wenn das Element den Fokus verliert. Wissen Sie?
Dan Nissenbaum
1
Wenn Sie mit "sofort" "immer dann, wenn eine Taste in der Eingabe gedrückt wird" meinen, suchen Sie nach den Ereignissen onkeyup, onkeypress und onkeydown, nicht nach onchange.
user2867288
6

Fügen Sie zur Vereinfachung eine benutzerdefinierte Funktion hinzu und rufen Sie sie auf, wann immer Sie möchten, dass eine Änderung des Werts auch eine Änderung auslöst

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

und

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

Oder Sie können die val-Funktion überschreiben, um die Änderung immer aufzurufen, wenn der val aufgerufen wird

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

Beispiel unter http://jsfiddle.net/r60bfkub/

Alireza Fattahi
quelle
Mein Browser beschwert sich über zu viele Rekursionen. Gibt es eine Lösung dafür?
Bhargav Nanekalva
Sie changewarten auf das Ereignis -event über ein Steuerelement und führen einen Rückruf aus, der (direkt oder indirekt) das changeEreignis -event über dasselbe Steuerelement erneut auslöst . Ich empfehle Ihnen, einen anderen Namen für das Ereignis zu verwenden, das Sie manuell auslösen (z. B. explicit.change), damit das Ereignis nicht erneut ausgelöst changewird, die Schleife verhindert wird und Sie dennoch auf das Ereignis reagieren können.
Kamafeather
3

Falls Sie nicht mit dem Standardänderungsereignis verwechseln möchten, können Sie Ihr benutzerdefiniertes Ereignis angeben

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

Sie können Folgendes tun, um das Ereignis bei einem festgelegten Wert auszulösen

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

Ich bin bei der Verwendung von CMB2 mit Wordpress auf dasselbe Problem gestoßen und wollte mich in das Änderungsereignis einer Metabox zum Hochladen von Dateien einbinden.

Falls Sie den Code, der die Änderung aufruft, nicht ändern können (in diesem Fall das CMB2-Skript), verwenden Sie den folgenden Code. Der Trigger wird aufgerufen, nachdem der Wert festgelegt wurde. Andernfalls funktioniert Ihr Änderungsereignishandler, aber der Wert ist der vorherige und nicht der festgelegte.

Hier ist der Code, den ich benutze:

(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
quelle
Das ist gut, aber können Sie zeigen, wie Sie es auf nur eine bestimmte Eingabe beschränken würden?
Jwebb
@jwebb Nicht ganz sicher, was du meinst? Wir überschreiben die Funktion jQuery val (). Sie binden einen Änderungsereignishandler an eine bestimmte Eingabe.
user2075039
Ich meine, @ user2075039, was ist, wenn die Seite mit der Funktion jQuery val () mehrere Eingaben enthält und Sie den benutzerdefinierten Änderungsereignishandler nicht an ALLE, sondern nur an eine von ihnen binden möchten?
Jwebb
@jwebb können Sie this.selectorin der überschreibenden $.fn.valFunktion nach einem bestimmten Selektor suchen (hängt davon ab, was für den Selektor verwendet wird). Dies ist das Beste, was ich gefunden habe, um dies nur für bestimmte Felder zu tun. Das einzige Problem ist, dass Sie wissen müssen, was sie für den Selektor verwenden
sMyles
1
$(":input#single").trigger('change');

Dies funktionierte für mein Skript. Ich habe 3 Combos und binde mit dem chainSelect-Ereignis. Ich muss 3 Werte per URL übergeben und standardmäßig alle Dropdown-Listen auswählen. Ich habe das benutzt

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

Und die erste Veranstaltung hat funktioniert.

Prashant Patil
quelle
10
Ich hoffe, du machst das nie in der realen Welt. Unnötig zu erwähnen, dass $ _GET ['was auch immer'] nicht vertrauenswürdig ist.
Denis V
1

Wenn Sie gerade die Auswahloption zu einem Formular hinzugefügt haben und das Änderungsereignis auslösen möchten, ist ein setTimeout erforderlich, andernfalls greift jQuery das neu hinzugefügte Auswahlfeld nicht auf:

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