Cara memicu suatu peristiwa setelah menggunakan event.preventDefault ()

156

Saya ingin mengadakan acara sampai saya siap untuk memecatnya misalnya

$('.button').live('click', function(e){

   e.preventDefault(); 

   // do lots of stuff

   e.run() //this proceeds with the normal event    

}

Apakah ada yang setara dengan run()fungsi yang dijelaskan di atas?

Mazatec
sumber
Perilaku default hanya terjadi setelah pawang Anda kembali. Tidak masuk akal untuk mencegah perilaku itu hanya untuk memungkinkannya nanti di penangan Anda.
Frédéric Hamidi
7
@ FrédéricHamidi Sayangnya, hal-hal async ($ .ajax, callbacks, dll.) Akan memungkinkan perilaku default terjadi.
vzwick

Jawaban:

165

Nggak. Setelah acara dibatalkan, dibatalkan.

Anda dapat memecat kembali acara nanti, menggunakan bendera untuk menentukan apakah kode khusus Anda sudah berjalan atau belum - seperti ini (harap abaikan polusi namespace terang-terangan):

var lots_of_stuff_already_done = false;

$('.button').on('click', function(e) {
    if (lots_of_stuff_already_done) {
        lots_of_stuff_already_done = false; // reset flag
        return; // let the event bubble away
    }

    e.preventDefault();

    // do lots of stuff

    lots_of_stuff_already_done = true; // set flag
    $(this).trigger('click');
});

Varian yang lebih umum (dengan manfaat tambahan untuk menghindari polusi namespace global) dapat menjadi:

function onWithPrecondition(callback) {
    var isDone = false;

    return function(e) {
        if (isDone === true)
        {
            isDone = false;
            return;
        }

        e.preventDefault();

        callback.apply(this, arguments);

        isDone = true;
        $(this).trigger(e.type);
    }
}

Pemakaian:

var someThingsThatNeedToBeDoneFirst = function() { /* ... */ } // do whatever you need
$('.button').on('click', onWithPrecondition(someThingsThatNeedToBeDoneFirst));

Plugin jQuery bonus super-minimalis dengan Promisedukungan:

(function( $ ) {
    $.fn.onButFirst = function(eventName,         /* the name of the event to bind to, e.g. 'click' */
                               workToBeDoneFirst, /* callback that must complete before the event is re-fired */
                               workDoneCallback   /* optional callback to execute before the event is left to bubble away */) {
        var isDone = false;

        this.on(eventName, function(e) {
            if (isDone === true) {
                isDone = false;
                workDoneCallback && workDoneCallback.apply(this, arguments);
                return;
            }

            e.preventDefault();

            // capture target to re-fire event at
            var $target = $(this);

            // set up callback for when workToBeDoneFirst has completed
            var successfullyCompleted = function() {
                isDone = true;
                $target.trigger(e.type);
            };

            // execute workToBeDoneFirst callback
            var workResult = workToBeDoneFirst.apply(this, arguments);

            // check if workToBeDoneFirst returned a promise
            if (workResult && $.isFunction(workResult.then))
            {
                workResult.then(successfullyCompleted);
            }
            else
            {
                successfullyCompleted();
            }
        });

        return this;
    };
}(jQuery));

Pemakaian:

$('.button').onButFirst('click',
    function(){
        console.log('doing lots of work!');
    },
    function(){
        console.log('done lots of work!');
    });
vzwick
sumber
4
.live hidup. Gunakan .on yang digunakan dalam contoh @Cory Danielson di bawah ini.
nwolybug
Ini lagi masuk ke dalam. Klik dan akhirnya saya melihat "terlalu banyak rekursi"
Himanshu Pathak
5
@ HimanshuPathak - Anda mungkin lupa mengatur lots_of_stuff_already_done = true;benderanya - jika tidak, tidak ada cara agar fungsi tetap berulang.
vzwick
73

Versi terbaru dari jawaban yang diterima.

Versi singkat:

$('#form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.lots_of_stuff_done ) {
        e.preventDefault();
        $.ajax({
            /* do lots of stuff */
        }).then(function() {
            // retrigger the submit event with lots_of_stuff_done set to true
            $(e.currentTarget).trigger('submit', { 'lots_of_stuff_done': true });
        });
    } else {
        /* allow default behavior to happen */
    }

});



Kasus penggunaan yang baik untuk sesuatu seperti ini adalah di mana Anda mungkin memiliki beberapa kode formulir lawas yang berfungsi, tetapi Anda diminta untuk meningkatkan formulir dengan menambahkan sesuatu seperti validasi alamat email sebelum mengirimkan formulir. Alih-alih menggali melalui kode pos formulir back-end, Anda bisa menulis API dan kemudian memperbarui kode front-end Anda untuk menekan API itu terlebih dahulu sebelum mengizinkan formulir untuk melakukan itu POST tradisional.

Untuk melakukan itu, Anda dapat menerapkan kode yang mirip dengan yang saya tulis di sini:

$('#signup_form').on('submit', function(e, options) {
    options = options || {};

    if ( !options.email_check_complete ) {

        e.preventDefault(); // Prevent form from submitting.
        $.ajax({
            url: '/api/check_email'
            type: 'get',
            contentType: 'application/json',
            data: { 
                'email_address': $('email').val() 
            }
        })
        .then(function() {
            // e.type === 'submit', if you want this to be more dynamic
            $(e.currentTarget).trigger(e.type, { 'email_check_complete': true });
        })
        .fail(function() {
            alert('Email address is not valid. Please fix and try again.');
        })

    } else {

        /**
             Do traditional <form> post.
             This code will be hit on the second pass through this handler because
             the 'email_check_complete' option was passed in with the event.
         */

        $('#notifications').html('Saving your personal settings...').fadeIn();

    }

});
Cory Danielson
sumber
1
"Alih-alih menggali melalui kode pos formulir back-end" ... Sebenarnya Anda harus tetap melakukannya, Anda tidak dapat mengandalkan validasi sisi klien saja.
Diego V
18

Anda dapat melakukan sesuatu seperti

$(this).unbind('click').click();
Rafael Oliveira
sumber
Ini adalah solusi yang sangat bagus - tetapi tampaknya tidak bekerja pada IE10 / 11; (
JonB
47
Mengapa Anda menyensor kata "sakit"?
Sean Kendle
Anda memicu klik tetapi bisakah Anda mengklik lagi?
Tom Anderson
16

Ganti properti isDefaultPreventedseperti ini:

$('a').click(function(evt){
  evt.preventDefault();

  // in async handler (ajax/timer) do these actions:
  setTimeout(function(){
    // override prevented flag to prevent jquery from discarding event
    evt.isDefaultPrevented = function(){ return false; }
    // retrigger with the exactly same event data
    $(this).trigger(evt);
  }, 1000);
}

IMHO, ini adalah cara paling lengkap untuk retriggering acara dengan data yang persis sama.

Tomislav Simić
sumber
etidak terdefinisi. seharusnya evt.preventDefault(). Saya mencoba mengedit, tetapi suntingan saya harus> 6 karakter dan saya baru saja menambahkan 2 :(
kevnk
3
@ kevnk, saya biasanya menyertakan uraian singkat hasil edit dalam bentuk komentar baris. Ini harus meningkatkan jumlah karakter yang dikirimkan.
kambuh
tidak tahu mengapa jawaban ini tidak lebih dipilih, ini sangat berguna. Bekerja dengan propagasi berhenti juga dengan event.isPropagationStopped = function(){ return false; };. Saya juga menambahkan properti khusus ke acara sehingga saya bisa mendeteksi di handler jika cek yang mencegah tindakan dilakukan sehingga tidak dibuat lagi. Bagus!
Kaddath
Saya digunakan untuk Bootstrap 4 Tab, Ini berfungsi dengan baik Terimakasih banyak. $ ('# v-pills-tab a'). on ('click', function (e) {e.preventDefault (); setTimeout (function () {e.isDefaultPrevented = function () {return false;} $ ( '# v-pills-home-tab'). on ('ditunjukkan.bs.tab', function () {$ ('. mainDashboard'). show (); $ ('# changePlans'). hide (); });}, 1000); $ (ini) .tab ('show');});
Surya R Praveen
8

Hal ini dimungkinkan untuk menggunakan currentTargetsatu event. Contoh menunjukkan bagaimana melanjutkan dengan mengirimkan formulir. Anda juga bisa mendapatkan fungsi dari onclickatribut dll.

$('form').on('submit', function(event) {
  event.preventDefault();

  // code

  event.currentTarget.submit();
});
Salvis Blūzma
sumber
kirim bukan fungsi yang valid
Devaffair
jika Anda memanggil submit()elemen yang sama, apakah Anda tidak akan mengembalikan kode `` $ ('form'). on ('submit') Anda dan mengulanginya lagi dan lagi?
Fanie Void
7

Hanya saja jangan melakukan e.preventDefault();, atau melakukannya secara kondisional.

Anda tentu tidak dapat mengubah ketika tindakan peristiwa asli terjadi.

Jika Anda ingin "membuat ulang" acara UI asli beberapa waktu kemudian (katakanlah, dalam panggilan balik untuk permintaan AJAX) maka Anda hanya perlu memalsunya dengan cara lain (seperti dalam jawaban vzwick) ... meskipun saya akan mempertanyakan kegunaan dari pendekatan semacam itu.

Lightness Races di Orbit
sumber
6

Jawaban yang lebih baru digunakan dengan terampil jQuery.one()

$('form').one('submit', function(e) {
    e.preventDefault();
    // do your things ...

    // and when you done:
    $(this).submit();
});

https://stackoverflow.com/a/41440902/510905

Jeruk13
sumber
3

selama "banyak hal" tidak melakukan sesuatu yang tidak sinkron, ini sama sekali tidak perlu - acara akan memanggil setiap penangan secara berurutan, jadi jika ada acara onklick pada elemen induk, ini akan diaktifkan setelah onclik- Peristiwa anak telah diproses sepenuhnya. javascript tidak melakukan semacam "multithreading" di sini yang membuat "menghentikan" peristiwa yang diperlukan neccessary. Kesimpulan: "menjeda" suatu peristiwa hanya untuk melanjutkannya di penangan yang sama tidak masuk akal.

jika "banyak hal" adalah sesuatu yang tidak sinkron, ini juga tidak masuk akal karena mencegah hal-hal yang tidak sinkron untuk melakukan apa yang seharusnya mereka lakukan (hal-hal yang tidak sinkron) dan menjadikannya bahave seperti segala sesuatunya berurutan (di mana kita kembali ke paragraf pertama saya) )

oezi
sumber
Proses di tengah asinkron, saya ingin memecat hasil dalam panggilan balik ajax ...
Mazatec
1
jika Anda harus menunggu permintaan-ajax, buatlah itu sinkron (untuk jquery, ada async-fag: api.jquery.com/jQuery.ajax ) ... tetapi membuat sinkron-ajax-permintaan adalah ide buruk di hampir setiap kasus, jadi akan lebih baik untuk menemukan solusi yang berbeda.
oezi
3

Pendekatan yang saya gunakan adalah ini:

$('a').on('click', function(event){
    if (yourCondition === true) { //Put here the condition you want
        event.preventDefault(); // Here triggering stops
        // Here you can put code relevant when event stops;
        return;
    }
    // Here your event works as expected and continue triggering
    // Here you can put code you want before triggering
});
Hokusai
sumber
2

Solusi yang diterima tidak akan berfungsi jika Anda bekerja dengan tag anchor. Dalam hal ini Anda tidak akan dapat mengklik tautan lagi setelah menelepon e.preventDefault(). Itu karena acara klik yang dihasilkan oleh jQuery hanya lapisan di atas acara browser asli. Jadi memicu acara 'klik' pada tag jangkar tidak akan mengikuti tautan. Alih-alih, Anda bisa menggunakan pustaka seperti simulasi-jquery yang memungkinkan Anda meluncurkan acara browser asli.

Rincian lebih lanjut tentang ini dapat ditemukan di tautan ini

Miguel Carvajal
sumber
1

Solusi lain adalah dengan menggunakan window.setTimeout di pendengar acara dan jalankan kode setelah proses acara selesai. Sesuatu seperti...

window.setTimeout(function() {
  // do your thing
}, 0);

Saya menggunakan 0 untuk periode karena saya tidak peduli menunggu.

Αλέκος
sumber
1

Saya tahu topik ini sudah lama tetapi saya pikir saya bisa berkontribusi. Anda dapat memicu perilaku default suatu peristiwa pada elemen tertentu kapan saja dalam fungsi penangan Anda jika Anda sudah tahu perilaku itu. Misalnya, ketika Anda memicu acara klik pada tombol reset, Anda benar-benar memanggil fungsi reset pada formulir terdekat sebagai perilaku default. Dalam fungsi handler Anda, setelah menggunakan fungsi preventDefault, Anda dapat memanggil kembali perilaku default dengan memanggil fungsi reset pada formulir terdekat di mana saja dalam kode handler Anda.

Patrik
sumber
0

Jika contoh ini dapat membantu, tambahkan "kustom konfirmasi popin" pada beberapa tautan (saya menyimpan kode "$ .ui.Modal.confirm", itu hanya contoh untuk panggilan balik yang menjalankan tindakan asli):

//Register "custom confirm popin" on click on specific links
$(document).on(
    "click", 
    "A.confirm", 
    function(event){
        //prevent default click action
        event.preventDefault();
        //show "custom confirm popin"
        $.ui.Modal.confirm(
            //popin text
            "Do you confirm ?", 
            //action on click 'ok'
            function() {
                //Unregister handler (prevent loop)
                $(document).off("click", "A.confirm");
                //Do default click action
                $(event.target)[0].click();
            }
        );
    }
);
Ronan Kerdudou
sumber