Чому подія зміни jquery не запускається, коли я встановлюю значення вибору за допомогою val ()?


377

Логіка в change()обробнику подій не виконується, коли значення задається val(), але воно запускається, коли користувач вибирає значення за допомогою миші. Чому це?

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

Відповіді:


589

Тому що для changeподії потрібна реальна подія браузера, ініційована користувачем, а не через код JavaScript.

Зробіть це замість цього:

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

або

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

1
Привіт, роблячи це оновлення вниз. але виклик onChange () рекурсивно.
Панкай

3
Я копаю цю відповідь. Це працює, але чи немає кращого способу з jQuery? Я впевнений, що ми ВСІ запам'ятаємо це робити кожного разу, коли ми змінюємо значення, яке встановлює обробник змін (сарказм). Можуть вирішити це краще рамки, які використовують прив'язку даних?
Джесс

@ user113716 Чи знаєте ви, як змінити його, не знаючи жодних значень?
BKSpurgeon

4
Я погоджуюся, що це правильна відповідь, але це абсолютно відстій і руйнує те, що я намагаюся зробити.
Дастін Пуассан

Спробуйте триггер $ ("# одиночний"). ({Type: "change", val: "Single2"})
user2901633

44

Я вважаю, що ви можете вручну запустити подію зміни за допомогою trigger():

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

Хоча чому це не спрацьовує автоматично, я поняття не маю.


Я не в змозі з цим працювати, також $ ("# одиночний"). Val ("Single2"). Change (); Я динамічно створюю спадне меню і змінюю його значення (Це працює добре для мене) Але коли я намагаюся викликати зміни, це не працює для мене.
Манееш Кумар

4
"Біт" запізнився, але він не спрацьовує автоматично, оскільки це призведе до нескінченних циклів. Подумайте$('#foo').change(function() { $( this ).val( 'whatever' ); });
JJJ

@Juhana Я думаю, що нескінченний цикл набагато простіше помітити, діагностувати та виправити, ніж val () загадково не вдається викликати "зміни" прив’язок.
іоно

Виклик .change () - це скорочення для виклику .trigger ('змінити').
Трайнко

9

Додавання цього фрагмента коду після val (), здається, працює:

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

6
Так, але вам не потрібно робити окремий добір DOM для цього $(":input#single"). Насправді ви насправді не повинні. Просто ланцюжок після цього .val(). Ви можете використовувати .trigger('change')або .change(). Вони точно такі ж.
користувач113716

8

Наскільки я можу прочитати в API. Подія запускається лише тоді, коли користувач натискає опцію.

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

Для полів вибору, прапорців та радіо кнопок подія запускається негайно, коли користувач робить вибір за допомогою миші, але для інших типів події відкладається, поки елемент не втратить фокус.


Які є альтернативи для інших типів елементів? Я хочу, щоб подія "зміни" негайно запускалася для inputелементів, а не тоді, коли елемент втрачає фокус. Чи ти знаєш?
Дан Ніссенбаум

1
Якщо під "негайно" ви маєте на увазі "кожного разу, коли натискається клавіша на вході", ви шукаєте події onkeyup, onkeypress та onkeydown, а не onchange.
користувач2867288

6

Щоб полегшити додавання спеціальної функції та зателефонувати їй коли завгодно, що зміна значення також призведе до зміни

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

і

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

Або ви можете змінити функцію val, щоб завжди викликати зміни, коли викликається val

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

Зразок на веб-сайті http://jsfiddle.net/r60bfkub/


Мій браузер скаржиться на занадто велику рекурсію, будь-яке виправлення для цього?
Bhargav Nanekalva

Ви слухаєте change-event над елементом управління та виконуєте зворотний виклик, який (прямо чи опосередковано) запускає знову change-event над тим самим елементом управління. Я пропоную вам використати інше ім’я для події, яку ви запускаєте вручну (наприклад explicit.change), щоб вона не повторювала changeповтор -event, запобігала циклу і все ж дозволяла вам реагувати на подію.
Kamafeather

3

Якщо ви не хочете змішуватися з подією зміни за замовчуванням, ви можете надати свою власну подію

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

щоб запустити подію на встановленому значенні, ви можете зробити

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

3

Я зіткнувся з тією ж проблемою під час використання CMB2 з Wordpress і хотів підключитись до події зміни метабокса завантаження файлів.

Тож у випадку, якщо ви не зможете змінити код, який викликає зміну (у цьому випадку сценарій CMB2), використовуйте код нижче. Тригер викликається ПІСЛЯ встановленого значення, в іншому випадку ваш подія зміниHandler буде працювати, але значення буде попереднім, а не встановленим.

Ось код, який я використовую:

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

Це добре, але чи можете ви показати, як ви обмежили його лише одним конкретним вкладом?
jwebb

@jwebb Не зовсім впевнений, що ти маєш на увазі? Ми переосмислюємо функцію jQuery val (). Ви прив'язуєте обробник подій зміни до певного входу.
user2075039

Я маю на увазі, @ user2075039, що робити, якщо на сторінці є кілька входів за допомогою функції jQuery val (), і ви не хочете прив'язувати користувальницький обробник подій зміни до ВСІХ, а лише до одного з них?
jwebb

@jwebb ви можете перевірити функцію, this.selectorщо переважає $.fn.val, для конкретного селектора (буде залежати від того, що використовується для селектора). Це найкраще, що я знайшов для цього лише для конкретних полів. Єдина проблема - ви повинні знати, що вони використовують для селектора
sMyles

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

Це працювало для мого сценарію. У мене є 3 комбо & пов'язувати з події chainSelect, мені потрібно передати 3 значення за URL-адресою та за замовчуванням вибрати всі випадаючі. Я цим користувався

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

І перша подія спрацювала.


10
Я сподіваюся, ви ніколи цього не робите в реальному світі. Зайве говорити, що $ _GET ["що завгодно"] не можна довіряти.
Денис V

1

Якщо ви просто додали опцію вибору у форму і хочете запустити подію зміни, я виявив, що setTimeout необхідний, інакше jQuery не підбирає щойно додане поле вибору:

window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.