jQuery模态确认对话框不提交表单。

11
我正在尝试在用户按下编辑表单上的删除按钮时弹出确认模态框。模态框正常弹出,但是当jQuery应该提交表单时,它什么也没做。我将type设置为"button",因为如果它是submit类型,模态框函数就无法阻止进程,它会立即删除用户。
HTML代码...
-- 编辑 --
(我添加了
标签)
<form action="/admin/edit-user" enctype="application/x-www-form-urlencoded" method="post" name="edit_user_form" id="edit_user_form">
...
<p><input type="submit" value="Save" name="submit" id="submit"/></p>
<p><input type="submit" value="Cancel" name="cancel" id="cancel"/></p>         
<p><input type="button" value="Delete User" name="delete_btn" id="delete_btn" onclick="confirmDeleteUser();"/></p>
...
</form>

...

<div id="dialog-modal" title="Confirm Delete User">
<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 0 0;"></span> Are you sure you wish to delete this user?</p>
<p>To continue editing, click cancel.</p>
</div>

JavaScript:

   function confirmDeleteUser()
    {    
        $('#dialog-modal').dialog({
            autoOpen: false,
            width: 400,
            modal: true,
            resizable: false,

            buttons: {
                "Cancel": function() {
                    $(this).dialog("close");
                    return false;
                },
                "Delete User": function() {
                    var self = $(this);
                    var form = $('#edit_user_form');
                    tmpElm = $('<input type="hidden" />');
                    tmpElm.attr('name', 'delete');
                    tmpElm.attr('id', 'delete');
                    tmpElm.val(true);
                    tmpElm.appendTo(form);
                    form.submit();
                    return true;
                }
            }
        });
        $('#dialog-modal').dialog('open');
    }

当我检查源代码时,我发现代码已经正确地添加了新的隐藏元素,但是提交似乎无法触发。我缺少哪个步骤?

1
你能同时添加FORM HTML标签吗? - Detect
点击“保存”或“取消”按钮是否成功提交表单? - Detect
表单是否附加了 onSubmit 事件? - Detect
@Detect:保存和取消成功提交表单,并使用“setTimeout…”也无济于事。 - ashurexm
如果您删除tmpElm代码,表单是否会提交? - Detect
显示剩余6条评论
5个回答

27

用不同的方式尝试一下。


HTML

您的HTML代码中包含以下内容:onclick="confirmDeleteUser();"

为什么要这样做呢?jQuery 应该让你的编程更加容易,而不是更加困难。

您的 HTML 代码应该是纯净的,不应该调用函数(除非您遇到极特殊的情况)。为什么不使用 jQuery 库将事件绑定到元素上,而不是将 JavaScript 函数调用混合到您的 HTML 中呢?您应该在 <script> 标签中使用类似于文档就绪语句之后的方式来完成这个操作。

$("#delete_btn").click(function(e){
    /*Code that runs on click of the "delete_btn" ID tag*/
});

如果您不熟悉jQuery选择器和事件,从这里开始阅读

另一个原因是为了防止文档未正确/完全加载而导致用户出现故障。


CSS

你也在HTML标签中使用了style="float:left; margin:0 7px 0 0;"吗?那太糟糕了,伙计。五个月后我该如何维护这段代码呢?

相反,使用CSS。

在你的<head>标签或CSS文件中,你需要添加如下条目:

.dialogAdjust {
    float: left;
    margin: 0 7px 0 0;
}

然后在你的HTML中,你需要这样写:

<span class="ui-icon ui-icon-alert dialogAdjust"></span>

现在,您可以根据自己的需要对这个东西进行微调。最好将类放在对话框div上,而不是单独的HTML元素上,在这种情况下,您绝对可以这样做。

JavaScript

好的,这是你的函数:

  function confirmDeleteUser()
    {    
        $('#dialog-modal').dialog({
            autoOpen: false,
            width: 400,
            modal: true,
            resizable: false,

            buttons: {
                "Cancel": function() {
                    $(this).dialog("close");
                    return false;
                },
                "Delete User": function() {
                    var self = $(this);
                    var form = $('#edit_user_form');
                    tmpElm = $('<input type="hidden" />');
                    tmpElm.prop('name', 'delete');
                    tmpElm.prop('id', 'delete');
                    tmpElm.val(true);
                    tmpElm.appendTo(form);
                    form.submit();
                    return true;
                }
            }
        });
        $('#dialog-modal').dialog('open');
    }

这里发生了什么?第一步,您应该尝试使用工具来衡量代码质量。两种流行的工具是 JSHintJSLint。您不需要像它们说的那样遵循所有规则来编写代码,但是在查找由于小错误导致的错误时,它非常有帮助。我喜欢 JSHint,所以我们将通过它来运行它。

这是输出:

Errors:

Line 17 tmpElm = $('<input type="hidden" />');
'tmpElm' is not defined.
Line 18 tmpElm.attr('name', 'delete');
'tmpElm' is not defined.
Line 19 tmpElm.attr('id', 'delete');
'tmpElm' is not defined.
Line 20 tmpElm.val(true);
'tmpElm' is not defined.
Line 21 tmpElm.appendTo(form);
'tmpElm' is not defined.

哎呀,看起来你的代码里有一个未定义的变量,这意味着它现在是全局的。全局变量是不好的,它们会破坏作用域并使你的代码以奇怪的方式运行。

我们需要解决这个问题。你应该总是在本地作用域中声明本地变量。这意味着在“删除用户”函数的顶部放置一个var tempElm;

取消函数包装器,你不需要它。你的代码应该在文档加载完成时创建对话框对象和代码,并在单击时打开对话框。在你原来的代码中发生了什么?每次点击那个按钮都会创建和打开对话框。问题在哪里?即使已经创建了对象,你仍在创建相同的对象。你一遍又一遍地创建相同的对象。在这个实现中,你可能注意不到它,但是除非你现在注意到这一点,否则你的设计将延续到其他地方。

那么,这是什么样子的?在你的<head>标签中,你应该看到类似以下的内容:

<script>
    
    /*
        This makes all the code inside
        run when the window is done loading, 
        not before, which may cause issues.
    */
    $(window).load(function(){    
    
    
        /*
            This sets up the dialog 
            as you've described before
        */
        $('#dialog-modal').dialog({
            autoOpen: false,
            width: 400,
            modal: true,
            resizable: false,

            buttons: {
                "Cancel": function() {
                    $(this).dialog("close");
                    return false;
                },
                "Delete User": function() {
                    var self = $(this);
                    var form = $('#edit_user_form');
                    //We've added the var infront of tepElem
                    var tmpElm = $('<input type="hidden" />');
                    tmpElm.prop('name', 'delete');
                    tmpElm.prop('id', 'delete');
                    tmpElm.val(true);
                    tmpElm.appendTo(form);
                    form.submit();
                    return true;
                }
            }
        });
        
        /*
            This is the part where I talked 
            about selectors and events in the HTML
        */
        $("#delete_btn").click(function(e){
            $('#dialog-modal').dialog('open');
        });
    });
</script>

当寻求帮助时,使用像jsFiddle这样的工具来发布JavaScript代码,以使其他人更容易帮助您。

这是我们迄今为止所做修改的jsFiddle。 如果您在JavaScript中进行了大量工作并想快速测试某些内容,请花点时间学习如何使用它。

以下是我希望您学习jsFiddle的原因:

您没有给我们足够的可用代码,导致我写了这篇关于代码质量和如何提问的巨大文章,尤其是当您发布悬赏时。

如果您需要帮助,请不要让人们费力去帮助您。除非有人完全疯了,否则您不会得到好的帮助。

jsFiddle要求您发布实际可用的代码(或不可用的代码),以便我们查看form.submit()是否存在问题,例如表单元素上的任何奇怪属性或属性,或者可能被排除的任何其他问题。

因此,让我们看看是什么破坏了您的“删除用户”功能。

function() {
    var self = $(this);
    var form = $('#edit_user_form');
    tmpElm = $('<input type="hidden" />');
    tmpElm.prop('name', 'delete');
    tmpElm.prop('id', 'delete');
    tmpElm.val(true);
    tmpElm.appendTo(form);
    form.submit();
    return true;
}
  • 你为什么声明了self?你从未使用过它。让我们把它去掉。
  • 你可以使用一种叫做chaining的东西,这完全取决于你。有些人讨厌它。
  • 你为类似选择的东西添加了一个全新的输入到表单中,我不确定这是否明智。我建议改变普通输入的值或使用另一种模式,这可能会导致很多问题,但出于问题的考虑,我会想象它是出于正确的原因而完成的。但是要小心,如果有人双击提交,那个输入就会出现两次。
  • form是DOM中使用的保留字,你应该避免使用它,以避免在变量和DOM API之间产生混淆。
  • 我们在点击哪个表单提交按钮?你有很多,jQuery不会猜测并希望最好的结果。

表单应该如何看起来:

W3解释了表单是什么以及其目的。

关键点:

  • 名称与值配对
  • 发送被点击的提交按钮,未被点击的提交按钮不会被发送。
  • 可以根据NAME和ID属性导航DOM

你的表单出现了一些奇怪的问题。

这是一个JavaScript可以理解如何提交的表单: http://jsfiddle.net/YS8uW/2/

这是JavaScript试图提交您的表单(简化为最基本的): http://jsfiddle.net/LfDXh/

这里有什么不同?

  • 你到处都有ID。
  • 你使用名称关键字

让我们看看你所做的事情,给某个东西一个ID为submit: http://jsfiddle.net/fdLfC/

当我们不使用它作为ID时会发生什么? http://jsfiddle.net/fdLfC/1/

啊哈。所以这很奇怪。

给它一个submit的id不会让你调用submit。一个正确的解释是,当你分配了ID和Name时,DOM已经重写了它,它正在尝试调用该元素。

如果您打开调试器之类的东西,您可以看到这一点,它会弹出一个警报:

类型错误:对象#的属性'submit'不是函数

避免使用关键字表示其他含义,您就不会陷入这些奇怪的陷阱。

非常感谢@MattMcDonald向我提供了this resource,其中解释了如何处理以及为什么NAME和ID属性会覆盖内置的HTML DOM方法。

也要做我说的其他事情。免责声明:每个人都将对我发动战争,说这并不绝对,您应该做所有这些事情,我同意,但我认为这篇文章足够长了,我们都将同意做这些事情是代码质量的一大进步,而不是倒退。最终还是由您决定,但请尽量避免将事物混合在一起形成一个巨大的混乱。同时考虑您的代码执行方式及其发生的情况。


2
我给你点赞是因为你有耐心写下了所有的内容。 - Joseph Yaduvanshi
4
我点赞是因为他既回答正确,又提供了背景知识,这比仅仅给出答案更有用。 - ashurexm

1

如果您确定它附加了隐藏输入,则问题必须在于使用重复的ID。 按钮和隐藏输入具有相同的ID。使它们不同,然后再试一次。


很好,你发现了id是相同的,但还是没有解决问题。我得到了完全相同的结果。 - ashurexm

0
不要问我为什么它能工作,我只能告诉你,在做了这个和那个并拆分代码的每个部分之后,最终我让它工作了。点击下面的链接查看演示。

http://jsfiddle.net/praveen_prasad/KaK5A/4/

我所做的更改是:从表单中删除了提交按钮的idname属性。

例如:

<input type="submit" value="Save" name="submit" id="submit"/>

将上面的内容改为下面的内容

<input type="submit" value="Save" />

JsFiddle演示注意事项:当您在模态框上单击删除用户时,表单将提交。jsfiddle会显示“错误404”,因为它找不到您正在发布表单的链接。打开Firebug并查看它实际上是发布到正确的URL。


1
我的回答解释了原因。如果你不理解,应该阅读它。 - Incognito

-1
"Delete User": function() {
    var self = $(this);
    var form = $('#edit_user_form');
    tmpElm = $('<input type="hidden" />');
    tmpElm.attr('name', 'delete');
    tmpElm.attr('id', 'delete');
    tmpElm.val(true); // HERE ----------------
    tmpElm.appendTo(form);
    form.submit();
    return true;
}

在指定的位置,应该是:

tmpElm.value(true);

或者

tmpElm.attr('value', 'true');

-1

我发现使用jQuery ajax和序列化表单值来处理我的表单提交并在确认后进行操作会更加清晰易懂。这样做的额外好处是避免了在

标签内部的按钮中产生不必要的表单提交。因此,代码看起来应该像这样:

<form id="edit_user_form">
...
<button id="submit_btn">Submit</button><br />
<button id="cancel_btn">Cancel</button><br />            
<button id="delete_btn">Delete</button>
...
</form>

然后是JavaScript:

$('#delete_btn').click(function() {

    $('#dialog-modal').dialog({
            autoOpen: false,
            width: 400,
            modal: true,
            resizable: false,
            buttons: {
                "Cancel": function() {
                    $(this).dialog("close");
                    return false;
                },
                "Delete User": function() {
                    $.ajax({                                                                                    
                url: "/admin/edit-user",
                type: "POST",
                            data: $('#edit_user_form).serialize(),
                error: function(XMLHttpRequest, textStatus, errorThrown)  {
                    alert("An error has occurred: " + errorThrown);
                },
                success: function(){
                        //Notify of success, redirect, etc.
                        }
                });
                }
            }
    });

});

所以,它仍然通过POST提交。现在可以异步发生(或不发生)。您可以在成功时“执行操作”而不更改页面,或者根据需要进行重定向。我使用一个“调度器”页面将其提交到我的面向对象框架,然后将输出返回到PHP调度程序,以进行json编码并作为字符串回显给AJAX调用以供成功使用。使用此模式,我只需要拥有一个页面来输出纯文本,其余部分可以驻留在我的OO类中,这些类无法直接通过ajax调用而不进行一些严重的修补(使用xajax)。


Ajax并不总是答案。在这种情况下,你是绕过问题而不是解决它。 - Incognito
@incognito,我同意Ajax并不总是答案。然而,这个解决方案确实回答了问题...因为它有效。所以我绝对没有回避任何问题。正如我所说,这个解决方案最适合我,因为我觉得它更容易理解和调试。各有所好。 - bpeterson76
这完全是绕过了。你没有解决任何他代码中的问题,只是给了他一个不同的方法来做这件事,而没有教他任何关于他所遇到的问题的知识。发送 AJAX 请求和提交表单之间有着巨大的区别。发送 ajax 请求并不能解决 dom 覆盖他的提交方法的问题。 - Incognito

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接