jQuery では、既に 1 つの「送信」バインディングがあるフォームに「送信」バインディングを追加しようとしていますが、既存のバインディングの前に新しい (2 番目の) バインディング (コールバック) を起動する必要があります。
バインディングを挿入して、既にアタッチされているバインディングの前に起動する方法はありますか?
バインドされた関数への文書化されていないアクセスを使用して、フォームに id があると仮定するとa
、次のようにハンドラー呼び出しの順序を逆にすることができます。
[].reverse.call($._data($('#a').get(0)).events.submit);
デモンストレーション(「Run with JS」をクリックし、コンソールを開き、「クリック」ボタンをクリックします)
この構造は文書化されておらず、保証がないことに注意してください。
これは、サポートされているパブリック インターフェイスではないことに注意してください。実際のデータ構造は、バージョンによって互換性がなくなる可能性があります。
したがって、実際の解決策は、最初のバインディング コードを変更することです。
あなたが使用することができます$._data( $("#myform")[0], "events" ).submit
クリック イベントのサンプル jsfiddle を参照してください。
私はこれが少し遅れていることを知っていますが、jQuery はこれを v1.7 以降で公開しました。私は会議を持っており、戻ってきたらこれを実際の例に変えます...戻ってきたら....幸運を祈ります。
#fiddle これはクリック イベントから実行されますが、考えて送信するように切り替えることができます
jsfiddle からの html の再投稿
<form>
<p>before click</p>
<button type="button">start</button>
</form>
jsfiddle から JavaScript を再投稿する
var $elem = $("button"), //jqElementObject
elem=$elem[0], //html element object
eventNameKey="click", //name of the event we want to alter
eventHandlerKey="handler"; //jQuery private object reference to get the actual function ref
$elem.click(function(ev){
//this happens somewhere else, pretend we can't control it per your comments
console.log("1");
ev.preventDefault();
$("p").text($("p").text()+"<div>first binding</div>");
});
//this is ours, we can control this
function submitControler(ev){
console.log("2");
ev.preventDefault();
$("p").text($("p").text()+"<div>second binding</div>");
//uncomment below to stop propogation
//return false;
}
$elem.click(submitControler); //actually register our event
$elem.click(function(ev){ //third event for some fun
ev.preventDefault();
$("p").text($("p").text()+"<div>third binding</div>");
});
var officialEvents = $._data(elem,"events"), //jQuery official Private events
ourSubmitEvents = $.Callbacks("unique stopOnFalse"); //default Callbacks values promises to behave like a standard events list, however, you want your event to fire first, then others to proceed if it returns true. also, no duplicates just because.
//I'm running out of time, so i went with a for loop. I wanted a way to find our event where the registration order was not guaranteed, feel free to go for something better
for(var event = officialEvents[eventNameKey].length-1; event >-1; event--){
if(officialEvents[eventNameKey][event][eventHandlerKey] ===submitControler){
ourSubmitEvents.add(officialEvents[eventNameKey][event][eventHandlerKey]);
console.log("added primary controler");
break;
}
}
//add in everyone else to our list, again, i'm out of time and a for loop was the first thought i had. feel free to improve
for(var event = 0; event < officialEvents[eventNameKey].length; event++){
if(officialEvents[eventNameKey][event][eventHandlerKey] !==submitControler){
ourSubmitEvents.add(officialEvents[eventNameKey][event][eventHandlerKey]);
console.log("added secondary controler");
}
}
//this is our event scheduler, it will be first to execute, and calls our manually re-ordered 'ourSubmitEvents' object. ('ourSubmitEvents' becomes 'ev.data')
$elem.on({"click":function(ev){
ev.preventDefault();
ev.data.fire(ev);
}},null,ourSubmitEvents);
//remove the other events, except the one we just registered.
$._data(elem,"events")[eventNameKey].splice(0,officialEvents[eventNameKey].length-1);