这可能不是你平常的“我如何捕获形式提交事件?” 题。
我试图精确地了解如何表单提交事件的jQuery,香草的Javascript处理,并且浏览器(IE / FF / Chrome浏览器/ Safari浏览器/歌剧) -和它们之间的关系。 ( 见我的其他问题。 )谷歌搜索后和实验的时间,我还是不能得出一个结论,要么是因为不和或含糊不清的。
我完成了一个脚本,以使表格无法提交,直到AJAX请求回来的网站形式的集成。
理想的情况是:
- 用户填写表单
- 表单提交 - 但没有以前绑定的事件处理程序被调用时,除了雷
- 我的处理程序,使(当然异步)API请求
- 用户确认从API响应验证结果
- 表单提交正常继续,自动调用之前遭打压的其他处理
我现在的理解是:(这些可能是错的,请若有指正)
- jQuery的结合形式提交事件处理程序的提交按钮
click
事件 - 事件处理程序上直接提交元件
click
事件(是否在像标记onclick=""
或使用jQuery绑定)首先被执行 - 在表格上的事件处理程序
submit
事件(是否在像标记onsubmit=""
或使用jQuery结合的)下一个被执行 - 调用
$('[type=submit]').click()
不调用表单的submit
事件,所以它的处理程序不会被调用 - 调用
$('form').submit()
不调用提交按钮的click
事件,所以它的处理程序不会被调用 - 然而不知何故,即点击提交按钮的用户最终绑定到窗体的调用处理程序
submit
事件......(但正如上面提到的,提交按钮调用点击不这样做) - 事实上, 任何方式向用户提交表单(通过提交按钮或者按回车键),在形式与jQuery绑定处理程序
submit
事件被称为...
现在,我是:
- 使用jQuery绑定到提交按钮的解除绑定处理
click
事件,同时保持对它们的引用 - 结合我自己的处理程序提交按钮的
click
事件,所以它执行第一 - 以在标记结合的任何处理程序使用
onclick=""
和onsubmit=""
(在它们各自的元素)和使用jQuery(这样它们矿之后执行)重新结合它们,然后设定的属性,以null
- 再结合自己的处理程序(步骤1),所以他们最后执行
其实,这一直是我自己的测试非常有效,让我的事件处理程序触发第一(必要的)。
这个问题,我的问题:
我的处理程序便会启动第一,正如预期(至今)。 问题是,我的处理是异步的,所以我必须抑制(的preventDefault / stopPropagation /等)的形式submit
或提交按钮click
那个调用它......直到API请求完成事件。 然后,当API请求回来,一切都OK,我需要重新调用的形式自动提交。 但是因为我的观察之上的,我怎么确保就好像它是一个自然的形式提交所有的事件处理程序?
什么是抓住他们的所有事件处理程序最清晰的方式,放矿,再重新调用的形式提交,使一切被称为在其正确的顺序?
又有什么区别,如果任何一个, $('form').submit()
和$('form')[0].submit()
(与同为$('[type=submit]').click()
和$('[type=submit]')[0].click()
TL;博士 ,什么是规范的,明确的,一个尺寸适合所有关于JavaScript / jQuery的/浏览器表单提交事件处理文档? (我不是在找书的建议。)
一些解释:我试图弥补的购物车结帐页面很多的Javascript,有时在那里的形式提交仅当用户单击该按钮(不提交按钮),在页面的底部,或有其他棘手的场景。 到目前为止,它已经相当成功,它只是重新调用提交的真正问题。
绑定到表单的使用jQuery提交处理程序,并阻止默认行为,那么,当你想提交表单,直接触发它的形式节点上。
$("#formid").submit(function(e){
// prevent submit
e.preventDefault();
// validate and do whatever else
// ...
// Now when you want to submit the form and bypass the jQuery-bound event, use
$("#formid")[0].submit();
// or this.submit(); if `this` is the form node.
});
通过调用submit
表单节点的方法,该浏览器的形式提交,而不会触发jQuery的提交处理。
这两个功能可以帮助您在了jQuery队列的前面,结合事件处理程序。 你仍然需要剥去联事件处理程序( onclick
, onsubmit
),并使用jQuery重新绑定它们。
// prepends an event handler to the callback queue
$.fn.bindBefore = function(type, fn) {
type = type.split(/\s+/);
this.each(function() {
var len = type.length;
while( len-- ) {
$(this).bind(type[len], fn);
var evt = $.data(this, 'events')[type[len]];
evt.splice(0, 0, evt.pop());
}
});
};
// prepends an event handler to the callback queue
// self-destructs after it's called the first time (see jQuery's .one())
$.fn.oneBefore = function(type, fn) {
type = type.split(/\s+/);
this.each(function() {
var len = type.length;
while( len-- ) {
$(this).one(type[len], fn);
var evt = $.data(this, 'events')[type[len]];
evt.splice(0, 0, evt.pop());
}
});
};
绑定执行Ajax调用提交处理程序:
$form.bindBefore('submit', function(event) {
if (!$form.hasClass('allow-submit')) {
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
// perform your ajax call to validate/whatever
var deferred = $.ajax(...);
deferred.done(function() {
$form.addClass('allow-submit');
});
return false;
} else {
// the submit event will proceed normally
}
});
绑定一个独立的处理程序,以阻止在点击事件[type="submit"]
直到你准备:
$form.find('[type="submit"]').bindBefore('click', function(event) {
if (!$form.hasClass('allow-submit')) {
// block all handlers in this queue
event.preventDefault();
event.stopPropagation();
event.stopImmediatePropagation();
return false;
} else {
// the click event will proceed normally
}
});
必须有解决这个许多方面 - 这里有一个。
在自定义事件队列它让你的Ajax功能(A)与所有其他(B,C,d等)分离出来,通过将只有A标准“提交”队列,B,C,d等。 这避免棘手阴谋在其他方面必要使B,C,d等依赖于A的异步响应。
$(function(){
var formSubmitQueue = 'formSubmitQueue';
//Here's a worker function that performs the ajax.
//It's coded like this to reduce bulk in the main supervisor Handler A.
//Make sure to return the jqXHR object that's returned by $.ajax().
function myAjaxHandler() {
return $.ajax({
//various ajax options here
success: function(data, textStatus, jqXHR) {
//do whatever is necessary with the response here
},
error: function(jqXHR, textStatus, errorThrown) {
//do whatever is necessary on ajax error here
}
});
}
//Now build a queue of other functions to be executed on ajax success.
//These are just dummy functions involving a confirm(), which allows us to reject the master deferred passed into these handlers as a formal variable.
$("#myForm").on(formSubmitQueue, function(e, def) {
if(def.state() !== 'rejected') {
if (!confirm('Handler B')) {
def.reject();
}
}
}).on(formSubmitQueue, function(e, def) {
if(def.state() !== 'rejected') {
if (!confirm('Handler C')) {
def.reject();
}
}
}).on(formSubmitQueue, function(e, def) {
if(def.state() !== 'rejected') {
if (!confirm('Handler D')) {
def.reject();
}
}
});
$("#myForm").on('submit', function(e) {
var $form = $(this);
e.preventDefault();
alert('Handler A');
myAjaxHandler().done(function() {
//alert('ajax success');
var def = $.Deferred().done(function() {
$form.get(0).submit();
}).fail(function() {
alert('A handler in the custom queue suppressed form submission');
});
//add extra custom handler to resolve the Deferred.
$form.off(formSubmitQueue+'.last').on(formSubmitQueue+'.last', function(e, def) {
def.resolve();
});
$form.trigger(formSubmitQueue, def);
}).fail(function() {
//alert('ajax failed');
});
});
});
DEMO (带模拟AJAX)
作为额外的奖励 ,任何自定义队列中的处理,可制成压制任何/所有后续处理程序和/或抑制形式提交。 只要选择合适的模式取决于真实需要什么:
模式1:
执行动作只有当所有前面的处理程序没有DEF拒绝。 并能抑制模式1和模式2的所有后续处理。
$("#myForm").on(formSubmitQueue, function(e, def) {
if(def.state() !== 'rejected') {
//actions as required here
if (expression) {
def.reject();
}
}
});
模式2:
执行动作只有当所有前面的处理程序没有DEF拒绝。 但不抑制如下处理。
$("#myForm").on(formSubmitQueue, function(e, def) {
if(def.state() !== 'rejected') {
//actions as required here
}
});
模式3:
无条件地执行其行动,但仍可以抑制模式1和模式2的所有后续处理。
$("#myForm").on(formSubmitQueue, function(e, def) {
//actions as required here
if (expression) {
def.reject();
}
});
模式4:
无条件地执行其行动,并没有打压下处理。
$("#myForm").on(formSubmitQueue, function(e, def) {
//actions as required here
});
笔记:
- 为了立即提交表单,而不处理队列中的其余部分推迟可能在这些处理程序来解决。 但在一般情况下,推迟将由“去年”处理程序添加到队列动态队列被触发(在处理程序后)之前得到解决。
- 在演示中,所有的处理程序是模式1。
以下是我最后做这一点,就已经很成功至今在众多的测试案例。 我学到了非常多的有关事件,特别是表单提交的事件,有关jQuery的。 我没有时间发布的所有我收集到的信息进行全面的百科全书,但这也足以令现在:
这是为SmartyStreets LiveAddress API jQuery插件在用户离开页面之前,这验证地址。
最成功的方法是通过抓取提交按钮的click
事件。 该片段下方在发现jquery.liveaddress.js
文件。 它得到尽可能多的事件处理程序尽可能(jQuery的,的onclick ---的onclick那些火第一),连根拔起它们的引用,扑通一声倒了自己( submitHandler
),和层别人在它上面。 它的成功合作对像TortugaRumCakes.com(结账)和MedicalCareAlert.com(首页及结帐)网站,以及其他许多人。
完整的代码是在GitHub上 。 这种特殊的段无二的“点击”提交按钮,但类似的代码是用来处理表单同时提交。 jQuery的submit()
函数显得较为专有的...但是这同时处理,确保它被调用,即使.submit()
以编程方式称为一个jQuery对象。
var oldHandlers, eventsRef = $._data(this, 'events');
// If there are previously-bound-event-handlers (from jQuery), get those.
if (eventsRef && eventsRef.click && eventsRef.click.length > 0)
{
// Get a reference to the old handlers previously bound by jQuery
oldHandlers = $.extend(true, [], eventsRef.click);
}
// Unbind them...
$(this).unbind('click');
// ... then bind ours first ...
$(this).click({ form: f, invoke: this }, submitHandler);
// ... then bind theirs last:
// First bind their onclick="..." handles...
if (typeof this.onclick === 'function')
{
var temp = this.onclick;
this.onclick = null;
$(this).click(temp);
}
// ... then finish up with their old jQuery handles.
if (oldHandlers)
for (var j = 0; j < oldHandlers.length; j++)
$(this).click(oldHandlers[j].data, oldHandlers[j].handler);