event.preventDefault()の使用後にイベントをトリガーする方法


156

発射する準備ができるまでイベントを開催したい

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

   e.preventDefault(); 

   // do lots of stuff

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

}

run()上記の機能に相当するものはありますか?


デフォルトの動作は、ハンドラーが戻った後にのみ発生します。後でハンドラで許可するだけでその動作を防止することはほとんど意味がありません。
フレデリック

7
@FrédéricHamidi残念ながら、非同期のもの($ .ajax、コールバックなど)ではデフォルトの動作が発生します。
vzwick '30 / 09/30

回答:


165

いいえ。イベントがキャンセルされると、キャンセルされます。

ただし、フラグを使用してカスタムコードがすでに実行されているかどうかを判断するために、後でこのように(露骨な名前空間汚染を無視してください)、イベントを再起動できます。

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');
});

より一般化されたバリアント(グローバルな名前空間の汚染を回避するという追加の利点がある)は次のとおりです。

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

使用法:

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

ボーナス付きの超ミニマルなjQueryプラグインPromise

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

使用法:

$('.button').onButFirst('click',
    function(){
        console.log('doing lots of work!');
    },
    function(){
        console.log('done lots of work!');
    });

4
.liveは廃止されています。以下の@Cory Danielsonの例で使用されている.onを使用します。
nwolybug 2015年

これは再び.clickの中に収まり、ついに "再帰が多すぎる"とわかりました
Himanshu Pathak

5
@HimanshuPathak-おそらくlots_of_stuff_already_done = true;フラグを設定するのを忘れました-そうでなければ、関数が再帰を続ける方法はありません。
vzwick 2016

73

承認された回答の最新バージョン。

簡単なバージョン:

$('#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 */
    }

});



このようなものの良い使用例は、機能するレガシーフォームコードがある場合ですが、フォームを送信する前にメールアドレス検証などを追加してフォームを拡張するように求められました。バックエンドフォームのポストコードを掘り下げる代わりに、APIを記述してから、フォームが従来のPOSTを実行する前に、そのAPIを最初にヒットするようにフロントエンドコードを更新できます。

これを行うには、ここで書いたものと同様のコードを実装できます。

$('#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();

    }

});

1
「バックエンドフォームのポストコードを掘り下げるのではなく」...実際にとにかくそうしなければならないので、クライアント側の検証だけに頼ることはできません。
Diego V


16

次のisDefaultPreventedようにプロパティをオーバーライドします。

$('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);
}

私見、これはまったく同じデータでイベントを再トリガーする最も完全な方法です。


e未定義です。する必要がありますevt.preventDefault()。編集を試みましたが、編集は6文字以上である必要があり、2 :(
kevnk

3
@kevnk、私は通常、編集の簡単な説明を行コメントの形式で含めます。これにより、送信される文字数が増えるはずです。
再帰

なぜこの回答がこれ以上賛成されなかったのかわからない、これは本当に便利です。伝播停止で動作しevent.isPropagationStopped = function(){ return false; };ます。また、イベントにカスタムプロパティを追加して、アクションを妨げるチェックが行われたかどうかをハンドラーで検出できるようにして、再度行われないようにしました。すごい!
Kaddath

私はBootstrap 4のタブに使用しましたが、完全に問題なく動作しました。どうもありがとう。$( '#v-pills-tab a')。on( 'click'、function(e){e.preventDefault(); setTimeout(function(){e.isDefaultPrevented = function(){return false;} $( '#v-pills-home-tab')。on( 'shown.bs.tab'、function(){$( '。mainDashboard')。show(); $( '#changePlans')。hide(); });}、1000); $(this).tab( 'show');});
Surya R Praveen

8

使用することが可能であるcurrentTargetevent。例では、フォームの送信を続行する方法を示します。同様に、onclick属性などから関数を取得できます。

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

  // code

  event.currentTarget.submit();
});

submitは有効な機能ではありません
Devaffair 2018

submit()同じ要素を呼び出す場合、「$( 'form')。on( 'submit')コードに戻って何度もやり直すことはありませんか?
Fanie Void

7

実行しないe.preventDefault();か、条件付きで実行してください。

元のイベントアクションが発生したときに変更することはできません。

しばらくして(たとえば、AJAXリクエストのコールバックで)元のUIイベントを「再作成」する場合は、(vzwickの回答のように)他の方法でそれを偽造する必要があります...そのようなアプローチの有用性に疑問を投げかける。



3

「たくさんのもの」が非同期で何かを実行していない限り、これは絶対に不要です。イベントは順番にすべてのハンドラーを順番に呼び出します。そのため、親要素にonklick-eventがある場合、onclik-の後に起動します子供のイベントは完全に処理されました。JavaScriptは、イベント処理の「停止」を必要とする、ある種の「マルチスレッド化」をここでは行いません。結論:同じハンドラーで再開するためだけにイベントを「一時停止」しても、意味がありません。

「ものの多く」非同期のものである場合、それはまた、彼らがやるべきことを非同期的に行うのを防ぎ(非同期のもの)、すべてが順番に並んでいるように振る舞うようにするので意味がありません(最初の段落に戻ります) )


真ん中のプロセスは...私はAjaxのコールバックで結果を発射したい、非同期です
Mazatec

1
ajaxリクエストを待つ必要がある場合は、それを同期化します(jqueryの場合は、async-fag:api.jquery.com/jQuery.ajax)...しかし、同期ajaxリクエストを作成することは、ほとんどすべての場合に悪い考えです。したがって、別の解決策を見つける方が良いでしょう。
oezi 2009

3

私が使用するアプローチはこれです:

$('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
});

2

アンカータグを使用している場合、承認されたソリューションは機能しません。この場合、を呼び出した後、リンクを再度クリックすることはできませんe.preventDefault()。これは、jQueryによって生成されたクリックイベントが、ネイティブブラウザーイベントの上にあるためです。したがって、アンカータグで「クリック」イベントをトリガーしても、リンクはたどられません。代わりに、ネイティブブラウザーイベントを起動できるjquery-simulateなどのライブラリを使用できます。

これに関する詳細はこのリンクで見つけることができます


1

別の解決策は、イベントリスナーで window.setTimeoutを使用し、イベントのプロセスが完了した後にコードを実行することです。何かのようなもの...

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

待ってもかまわないので期間は0を使います。


1

このトピックが古いことは知っていますが、貢献できると思います。特定の要素のイベントのデフォルトの動作は、その動作がすでにわかっている場合は、ハンドラー関数でいつでもトリガーできます。たとえば、リセットボタンのクリックイベントをトリガーすると、実際には最も近いフォームのリセット関数をデフォルトの動作として呼び出します。ハンドラー関数では、preventDefault関数を使用した後、ハンドラーコード内の最も近いフォームでリセット関数を呼び出すことにより、デフォルトの動作を呼び出すことができます。


0

この例が役立つ場合は、いくつかのリンクに「カスタム確認ポップイン」を追加します(「$ .ui.Modal.confirm」のコードを保持します。これは、元のアクションを実行するコールバックの単なる例です)。

//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();
            }
        );
    }
);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.