ASP.NET MVC Ajax.BeginForm不起作用

时间:2021-09-19 03:19:38
<script src="../../Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script>

<script type="text/javascript">
    function loginOK()
    {
        var item = document.getElementById('statusLabel');
        item.innerHTML = "OK";
        document.getElementById('LoadImg').style.visibility = 'hidden';
    }

    function process()
    {
        var lab = document.getElementById('statusLabel');
        lab.innerHTML = 'Checking...';
        lab.style.color = 'Black';
        document.getElementById('LoadImg').style.visibility = 'visible';
    }

    function fail()
    {
        var lab = document.getElementById('statusLabel');
        lab.innerHTML = 'Login is being used';
        lab.style.color = 'Red';
        document.getElementById('LoadImg').style.visibility = 'hidden';
    }
</script>

 <div style="width:30%; float:left;">
     <label for="Login">Login:</label>
     <%= Html.TextBoxFor(model=>model.Login) %>
     <%= Html.ValidationMessageFor(model=>model.Login) %>

     <img id="LoadImg" alt="" src="../../Content/Images/ajax-loader.gif" style="visibility:hidden;"/>
     <br />
     <label id="statusLabel" />
     <br />
     <%=Ajax.ActionLink("CheckLogin","CheckLoginAvailability", "Account",
        new AjaxOptions { UpdateTargetId = "statusLabel", OnBegin = "process", OnFailure = "fail", OnSuccess="loginOK"})%>
 </div>

and, in the AccountController:

并且,在AccountController中:

    [AcceptVerbs(HttpVerbs.Post)]
    public void CheckLoginAvailability(string login)
    {
        //do some job
    }

And, FireBug says that /Account/CheckLoginAvailability is not found. Also, after callback that ActionLink is hidden. Why ?

并且,FireBug说没有找到/ Account / CheckLoginAvailability。此外,在回调后隐藏了ActionLink。为什么?

2 个解决方案

#1


3  

You are talking about Ajax.BeginForm in your question but this is nowhere to be seen in the markup you provided. There are a couple of issues that I can see with your code:

您正在讨论Ajax.BeginForm,但在您提供的标记中无处可见。我可以在您的代码中看到几个问题:

  1. Your action method doesn't return an ActionResult. Yeah I know, you will say that this is possible, right, but that's against any good practices, conventions and rendering your controllers unit-test friendly.
  2. 您的操作方法不会返回ActionResult。是的,我知道,你会说这是可能的,对,但这是违反任何良好的做法,惯例和使你的控制器单元测试友好。

  3. You are using Microsoft Ajax which will mix markup and javascript which IMHO is bad for multiple reasons: increasing bandwidth which of course leads to decreased performance, incapacity to externalize javascript into separate files in order to cache them by client browsers, having to write things like document.getElementById, innerHTML, style.color, style.visibility, etc... which is not guaranteed to work cross browser.
  4. 您使用的是混合了标记和javascript的Microsoft Ajax,其中恕我直言的原因有多种:增加带宽当然会导致性能下降,无法将javascript外部化为单独的文件以便通过客户端浏览器缓存它们,不得不编写像document.getElementById,innerHTML,style.color,style.visibility等...不能保证跨浏览器工作。

Here's what I would suggest you to improve this. While this doesn't answer your question, take it as an alternative approach.

以下是我建议你改进的内容。虽然这不能回答您的问题,但请将其作为替代方法。

As always the first thing to deal with is to define a model which in your case might look something like this:

与往常一样,首先要处理的是定义一个模型,在您的情况下可能看起来像这样:

public class LoginViewModel
{
    public string Login { get; set; }
}

Of course you might wish to add other fields such as Password, but this is out of scope for the moment. The next step is to write a controller dealing with this model (in parallel you should be already setting a unit-test for the future controller to prepare the ground):

当然,您可能希望添加其他字段,例如密码,但目前这超出了范围。下一步是编写一个处理这个模型的控制器(同时你应该已经为未来的控制器设置单元测试以准备接地):

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Simply return the Login form
        return View(new LoginViewModel());
    }

    [HttpPost]
    public ActionResult Index(LoginViewModel model)
    {
        // Deal with the actual authentication, etc...
        throw new NotImplementedException();
    }

    [HttpPost]
    public ActionResult CheckLoginAvailability(LoginViewModel model)
    {
        // TODO: query your datasource to determine whether 
        // model.Login is taken
        // For this purpose we will suppose that it is taken
        bool isLoginTaken = true;

        // return a JSON object containing the result
        return Json(new { IsLoginTaken = isLoginTaken });
    }
}

The last part is to paint the screen:

最后一部分是绘制屏幕:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<SomeNs.Models.LoginViewModel>" %>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Login</title>
    <!-- Use a separate CSS to avoid mixing markup with styling -->
    <link rel="stylesheet" type="text/css" href="<%: Url.Content("~/content/site.css") %>" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
    <!-- Always use HTML helpers when dealing with Urls -->
    <script type="text/javascript" src="<%: Url.Content("~/scripts/login.js") %>"></script>
</head>
<body>
    <% using (Html.BeginForm()) { %>
        <%: Html.LabelFor(x => x.Login) %>:
        <%: Html.TextBoxFor(x => x.Login) %>
        <%: Html.ValidationMessageFor(x => x.Login) %>
        <br/>
        <!-- Always use HTML helpers when dealing with Urls -->
        <img id="loadImg" alt="" src="<%: Url.Content("~/content/images/ajax-loader.gif") %>" style="display:none;" />
        <br />
        <div id="statusLabel"></div>
        <br />
        <!-- Give this link an id so that we can easily identify it from javascript -->
        <%: Html.ActionLink("CheckLogin", "CheckLoginAvailability", "Home", null, new { id = "checkLogin" })%>
        <input type="submit" value="Login" />
    <% } %>
</body>
</html>

And the last part is to unobtrusively attach our javascript (using jQuery of course) in the login.js file:

最后一部分是在login.js文件中不引人注意地附加我们的javascript(当然使用jQuery):

// When the DOM is ready
$(function () {
    // Attach a click handler to the checkLogin link
    $('a#checkLogin').click(function () {
        // When this link is clicked send an AJAX POST request
        // to the address this link is pointing to
        $.ajax({
            type: 'POST',
            url: this.href,
            // Pass as parameter in the POST body the login
            // entered by the user
            data: { login: $('#Login').val() },
            beforeSend: function () {
                // show the spinner image before sending any AJAX request
                // to inform the user of an ongoing activity
                $('#loadImg').show();
            },
            complete: function () {
                // hide the spinner image when the AJAX request completes
                // no matter if it succeeded or not
                $('#loadImg').hide();
            },
            success: function (result) {
                // if the AJAX request succeeds
                // query the IsLoginTaken property
                // of the resulting JSON object
                if (result.IsLoginTaken) {
                    // Show the status label with red if the login is taken
                    $('#statusLabel').html('Login is being used').css('color', 'red');

                } else {
                    // Show the status label in black if the login is not taken
                    $('#statusLabel').html('OK').css('color', 'black');
                }
            }
        });
        return false;
    });
});

#2


1  

As @SLaks says actions can return void but, I think the action signature is such that it is required to return an action result and you can return EmptyResult if you don't want to return anything.

正如@SLaks所说,操作可以返回void,但我认为操作签名是这样的,它需要返回一个操作结果,如果你不想返回任何东西,你可以返回EmptyResult。

see this http://www.asp.net/mvc/tutorials/asp-net-mvc-controller-overview-cs

见http://www.asp.net/mvc/tutorials/asp-net-mvc-controller-overview-cs

try changing your AccountController to

尝试将AccountController更改为

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CheckLoginAvailability(string login)
{
   //do some job
   return new EmptyResult();
}

#1


3  

You are talking about Ajax.BeginForm in your question but this is nowhere to be seen in the markup you provided. There are a couple of issues that I can see with your code:

您正在讨论Ajax.BeginForm,但在您提供的标记中无处可见。我可以在您的代码中看到几个问题:

  1. Your action method doesn't return an ActionResult. Yeah I know, you will say that this is possible, right, but that's against any good practices, conventions and rendering your controllers unit-test friendly.
  2. 您的操作方法不会返回ActionResult。是的,我知道,你会说这是可能的,对,但这是违反任何良好的做法,惯例和使你的控制器单元测试友好。

  3. You are using Microsoft Ajax which will mix markup and javascript which IMHO is bad for multiple reasons: increasing bandwidth which of course leads to decreased performance, incapacity to externalize javascript into separate files in order to cache them by client browsers, having to write things like document.getElementById, innerHTML, style.color, style.visibility, etc... which is not guaranteed to work cross browser.
  4. 您使用的是混合了标记和javascript的Microsoft Ajax,其中恕我直言的原因有多种:增加带宽当然会导致性能下降,无法将javascript外部化为单独的文件以便通过客户端浏览器缓存它们,不得不编写像document.getElementById,innerHTML,style.color,style.visibility等...不能保证跨浏览器工作。

Here's what I would suggest you to improve this. While this doesn't answer your question, take it as an alternative approach.

以下是我建议你改进的内容。虽然这不能回答您的问题,但请将其作为替代方法。

As always the first thing to deal with is to define a model which in your case might look something like this:

与往常一样,首先要处理的是定义一个模型,在您的情况下可能看起来像这样:

public class LoginViewModel
{
    public string Login { get; set; }
}

Of course you might wish to add other fields such as Password, but this is out of scope for the moment. The next step is to write a controller dealing with this model (in parallel you should be already setting a unit-test for the future controller to prepare the ground):

当然,您可能希望添加其他字段,例如密码,但目前这超出了范围。下一步是编写一个处理这个模型的控制器(同时你应该已经为未来的控制器设置单元测试以准备接地):

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // Simply return the Login form
        return View(new LoginViewModel());
    }

    [HttpPost]
    public ActionResult Index(LoginViewModel model)
    {
        // Deal with the actual authentication, etc...
        throw new NotImplementedException();
    }

    [HttpPost]
    public ActionResult CheckLoginAvailability(LoginViewModel model)
    {
        // TODO: query your datasource to determine whether 
        // model.Login is taken
        // For this purpose we will suppose that it is taken
        bool isLoginTaken = true;

        // return a JSON object containing the result
        return Json(new { IsLoginTaken = isLoginTaken });
    }
}

The last part is to paint the screen:

最后一部分是绘制屏幕:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<SomeNs.Models.LoginViewModel>" %>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Login</title>
    <!-- Use a separate CSS to avoid mixing markup with styling -->
    <link rel="stylesheet" type="text/css" href="<%: Url.Content("~/content/site.css") %>" />
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
    <!-- Always use HTML helpers when dealing with Urls -->
    <script type="text/javascript" src="<%: Url.Content("~/scripts/login.js") %>"></script>
</head>
<body>
    <% using (Html.BeginForm()) { %>
        <%: Html.LabelFor(x => x.Login) %>:
        <%: Html.TextBoxFor(x => x.Login) %>
        <%: Html.ValidationMessageFor(x => x.Login) %>
        <br/>
        <!-- Always use HTML helpers when dealing with Urls -->
        <img id="loadImg" alt="" src="<%: Url.Content("~/content/images/ajax-loader.gif") %>" style="display:none;" />
        <br />
        <div id="statusLabel"></div>
        <br />
        <!-- Give this link an id so that we can easily identify it from javascript -->
        <%: Html.ActionLink("CheckLogin", "CheckLoginAvailability", "Home", null, new { id = "checkLogin" })%>
        <input type="submit" value="Login" />
    <% } %>
</body>
</html>

And the last part is to unobtrusively attach our javascript (using jQuery of course) in the login.js file:

最后一部分是在login.js文件中不引人注意地附加我们的javascript(当然使用jQuery):

// When the DOM is ready
$(function () {
    // Attach a click handler to the checkLogin link
    $('a#checkLogin').click(function () {
        // When this link is clicked send an AJAX POST request
        // to the address this link is pointing to
        $.ajax({
            type: 'POST',
            url: this.href,
            // Pass as parameter in the POST body the login
            // entered by the user
            data: { login: $('#Login').val() },
            beforeSend: function () {
                // show the spinner image before sending any AJAX request
                // to inform the user of an ongoing activity
                $('#loadImg').show();
            },
            complete: function () {
                // hide the spinner image when the AJAX request completes
                // no matter if it succeeded or not
                $('#loadImg').hide();
            },
            success: function (result) {
                // if the AJAX request succeeds
                // query the IsLoginTaken property
                // of the resulting JSON object
                if (result.IsLoginTaken) {
                    // Show the status label with red if the login is taken
                    $('#statusLabel').html('Login is being used').css('color', 'red');

                } else {
                    // Show the status label in black if the login is not taken
                    $('#statusLabel').html('OK').css('color', 'black');
                }
            }
        });
        return false;
    });
});

#2


1  

As @SLaks says actions can return void but, I think the action signature is such that it is required to return an action result and you can return EmptyResult if you don't want to return anything.

正如@SLaks所说,操作可以返回void,但我认为操作签名是这样的,它需要返回一个操作结果,如果你不想返回任何东西,你可以返回EmptyResult。

see this http://www.asp.net/mvc/tutorials/asp-net-mvc-controller-overview-cs

见http://www.asp.net/mvc/tutorials/asp-net-mvc-controller-overview-cs

try changing your AccountController to

尝试将AccountController更改为

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CheckLoginAvailability(string login)
{
   //do some job
   return new EmptyResult();
}