ASP.NET MVC Ajax.BeginForm吃点击提交按钮的参数。看起来像虫子

时间:2009-04-24 20:47:45

标签: asp.net-mvc ajax

如果您使用的Ajax.BeginForm()具有与此类似的多个提交按钮:

// View.aspx
<% using (Ajax.BeginForm("Action", "Controller", 
           new AjaxOptions { UpdateTargetId = "MyControl",  }))
{ %>
    <span id="MyControl">
       <% Html.RenderPartial("MyControl"); %>
    </span>
<% } %>

//MyControl.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<input name="prev" type="submit" value="prev" />
<input name="next" type="submit" value="next" />
//...

所有内容都提交给控制器,但请求中没有单击提交按钮的参数。换言之,请求[“next”]和Request [“prev”]始终为空。

我查看了Microsoft.MvcAjax.js中的JavaScript,看起来函数Sys_Mvc_MvcHelpers $ _serializeForm完全跳过了'submit'类型的输入。

这根本不符合逻辑。你怎么能找到点击的按钮?

对我来说这看起来像个错误。是否有任何逻辑上的理由跳过这些表格参数?

5 个答案:

答案 0 :(得分:4)

更新:2009-11-21 我下载了MVC Release 2 Preview 2,看看是否修复了这个问题。 我做了一个快速测试,发现了与MVC Release 2 Preview 1类似的结果。 我不相信它已经修好了。

更新时间:2009-08-07 我下载了MVC Release 2 Preview 1并查看是否修复了此问题。 我在脚本MicrosoftMvcAjax.debug.js中看到一个名为 _serializeSubmitButton 的新函数,我看到当Ajax.BeginForm()呈现输出时有一个onclick事件,但是当这个事件触发时会产生错误“ Microsoft JScript运行时错误:'Sys.Mvc.AsyncForm'为null或不是对象“。

简而言之,它看起来像是尝试修复,但它还没有工作,或者我需要做更多的事情。坏消息是,如果不是后者,那么在修复完成之前,Ajax Forms将被打破。

更新时间:2009-05-07 我今天收到了微软的反馈,确认这是一个错误。他们记录了这个缺陷,并表示他们希望在将来的版本中修复它。

作为参考,我将留下我提交给微软的调查细节。这篇长篇文章的应用可能对任何试图创作作品的人都有用..

MVC中的Ajax支持存在一些问题。为了说明,请考虑网络上几个例子中说明的模式:

//===========
// View.aspx
//===========
<% using (Ajax.BeginForm("Action", "Controller", 
    new AjaxOptions { UpdateTargetId  = "MyControl", HttpMethod = "POST"}))
{ %>
    <span id="MyControl">
       <% Html.RenderPartial("MyControl"); %>
    </span>
<% } %>

//================
// MyControl.ascx
//================
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<input name="startIndex" type="hidden" value="0" />
<%= Ajax.ActionLink("Prev", "PrevAction",
    new AjaxOptions() { UpdateTargetId="MyControl", HttpMethod="POST"}) %>
<%= Ajax.ActionLink("Next", "NextAction", 
    new AjaxOptions() { UpdateTargetId="MyControl", HttpMethod="POST"}) %>
//...

<强>预期:
这只是一个列表,用户可以在不更新整个页面的情况下前后翻页。

鉴于此设置。我希望2个链接标记为“上一个”和“下一个”。单击“上一个”应该将控制器中的PrevAction方法作为一个帖子触发,并且名为“startIndex”的隐藏字段中的值应该在请求参数中可用。单击Next链接时,我期望得到类似的结果。

<强>实际
实际情况是,请求对象包含NONE的表单参数,即使它显示它作为POST进入。

为了使用动作链接获取任何参数,必须通过包含参数的ActionLink变体显式提供它们。当使用它时,参数成为链接URL的一部分,这违背了POST的目的。

那为什么javascript错了?
我挖了javascript代码,用于处理我用问题发布的示例的提交,我现在更好地理解为什么它不处理它。原因似乎与他们连接事件的方式以及我认为是Internet Explorer的缺点有关。

它目前的工作方式是Ajax.BeginForm()帮助器类生成一个带有 onsubmit() 函数的表单标记,以拦截表单提交事件。当用户点击提交按钮时, onsubmit() 功能会触发并接收参数,其中一个参数是事件。

MicrosoftMvcAjax脚本查看事件,捆绑应该提交的表单属性并将请求发送到服务器。问题是,根据WC3标准,只应发布成功的控件。在提交按钮的情况下,这是实际单击的按钮。在Internet Explorer下,无法确定实际导致提交事件的按钮,因此脚本只会跳过所有提交按钮。

(在Firefox中,该事件包含一个名为“explictOriginalTarget”的属性,该属性指向实际上首先导致该事件的按钮)

什么是修复?
微软应该修复它。但是,如果我们需要更快的东西,我相信唯一的选择是破解MicrosoftMvcAjax脚本以不同方式连接事件。我发现表单可以连接到一个mousedown事件的句柄,其中单击的按钮可以保存在全局变量中,其中onsubmit处理程序可以将其插入post参数。

这是我正在测试的一些代码来说明这种技术。我已经确认它在IE8和FireFox中都有效,但我还没有尝试将其破解成MVC Ajax脚本......如果我有更多的时间。我可以在这里公布结果。

   <script type="text/javascript">
     var _clicked = "";
     function onSubmit(e) {
       var targ;
       if (!e) var e = window.event;
       if (e.target) targ = e.target;
       else if (e.srcElement) targ = e.srcElement;
       if (targ.nodeType == 3) //defeat Safari bug
           targ = targ.parentNode;
       alert("OnSubmit:" + _clicked + " was clicked.");
       return false;
     }
     function Click(e) {
       var targ;
       if (!e) var e = window.event;
       if (e.target) targ = e.target;
       else if (e.srcElement) targ = e.srcElement;
       if (targ.nodeType == 3) //defeat Safari bug
           targ = targ.parentNode;
       _clicked = targ.name;
       return true;
   }

   <form action="/Home/StandardForm" method="post" 
    onsubmit="onSubmit(event)" onmousedown="Click(event)">
      <input type="submit" name="StdPrev" value="StdPrev" />
      <input type="submit" name="StdNext" value="StdNext" />
   </form>

答案 1 :(得分:3)

为了使您的提交按钮成为规范中的“成功”控件,必须在表单元素中定义它们:

http://www.w3.org/TR/html401/interact/forms.html#successful-controls

如果您无法在表单中嵌套提交按钮,则可能需要使用javascript(或jquery)提交表单并传入另一个参数以指示单击了哪个按钮。

答案 2 :(得分:1)

我想这已在MVC 2中得到修复(或者它从未被破坏)。只需确保您的HTML标记有效。以下示例应显示其有效。

<强> Vote.aspx:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Vote</title>
</head>
<body>

<%using (Ajax.BeginForm("Vote", "Voting", new AjaxOptions { UpdateTargetId = "message" }))
  { %>
    <%= Html.Hidden("itemId", "1")%>
    <p>I love ASP.NET MVC!</p>

    <input type="submit" name="voteValue" value="+" />
    <input type="submit" name="voteValue" value="-" />
<%} %>

<p id="message"><%= TempData["message"] %></p>


<script type="text/javascript" src="<%= Url.Content("~/Scripts/MicrosoftAjax.js")%>"></script>
<script type="text/javascript" src="<%= Url.Content("~/Scripts/MicrosoftMvcAjax.js")%>"></script>

</body>
</html>

<强> VotingController.aspx:

using System.Web.Mvc;

namespace Examples.FormWithMultipleSubmitButtons.Controllers
{
    public class VotingController : Controller
    {
        public ViewResult Vote()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Vote(int itemId, string voteValue)
        {
            switch(voteValue)
            {
                case "+":
                    TempData["message"] = "You voted up.";
                    break;
                case "-":
                    TempData["message"] = "You voted down.";
                    break;
                default:
                    TempData["message"] = "Your vote was not recognized.";
                    break;
            }

            if(Request.IsAjaxRequest())
            {
                return Content(TempData["message"].ToString());
            }
            else
            {
                return View();
            }
        }
    }
}

我今天(2010年10月8日)遇到了同样的问题,我的表单有多个提交按钮。 HTML没有验证。我把它清理干净了。它仍然没有验证(但错误比原始错误少),现在提交了点击按钮的值。

答案 3 :(得分:0)

可能的解决方法可能是将单独表单中的每个按钮路由到控制器上的不同操作。 不理想,但可以工作。

答案 4 :(得分:0)

我做了以下事情:

            <input id="btnSubmit" name="btnSubmit" type="hidden" value="" />
            <input type="submit" name="btnSubmit" value="Delete" id = "btnDelete"  onclick="$('#btnSubmit').attr('value','Delete');"/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
            <input type="submit" name="btnSubmit" value="Save New" id = "btnSaveNew"  onclick="$('#btnSubmit').attr('value','Save New');"/>
            <input type="submit" name="btnSubmit" value="Save" id = "btnSave" onclick="$('#btnSubmit').attr('value','Save');"/>

即。定义了一个ID为“btnSubmit”的隐藏输入类型,并在每个按钮上添加了onclick事件,如onclick =“$('#btnSubmit')。attr('value','Delete');”。这似乎有效 因为我能够获得在控制器中点击的按钮的值:

public ActionResult SaveCreateBlot(string btnSubmit) {

}