tags:

views:

180

answers:

2

Hi, I have that code:

<script src="../../Scripts/MicrosoftMvcAjax.debug.js" type="text/javascript"></script>
<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:

    [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 ?

+1  A: 

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.

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

try changing your AccountController to

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

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:

  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. 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.

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"&gt;&lt;/script&gt;
    <!-- 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:

// 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;
    });
});
Darin Dimitrov
As I remember, there were always problems for me with Ajax.BeginForm (the same code worked different) so the second thought was to use jQuery. Your code looks very interesting, I'll check it. Thanks :)
Tony
Everything works fine, but why after success the input is hidden ? Even if I write success: {... $('#checkLogin').show();} it doesn't show
Tony
Notice how the `statusLabel` is declared in my code: `<div id="statusLabel"></div>` instead of `<div id="statusLabel" />` or `<label id="statusLabel" />`. I think this could make a difference.
Darin Dimitrov
wow, it resolved the problem. I didn't realize that it could made the difference
Tony
@Tony, while this resolves the problem I cannot really explain the technical aspect of it. Maybe someone more experienced with jQuery and the DOM could shed more light.
Darin Dimitrov