Joseph
Joseph

Reputation: 25513

What is the best way to implement AJAX using ASP.NET MVC and jquery?

I'm trying to figure out the best way to make an AJAX call to perform some action, and then do some jquery effect magic to make it look like something is happening.

This is the basic idea: I have a link that when the user clicks it I need to update my model to say that the user is interested in an item (on the server side). However, I would also like to fade out the link (it's a checkbox image I made), change classes around and then fade the link back in. Behavior is like this: when you're not interested in an item the link looks like an empty box, when you hover over it the check appears, when they click on it the link fades out and comes back with the check in the box, and now when they hover over it the check disappears (the behavior reverses).

My problem is the link doesn't seem to be able to keep track of where it is (whether its in a checked state or an unchecked state).

I've tried doing this multiple ways.

Example A:

<a href="#" onclick="oncheck(this,<%= item.ID %>)" class="notchecked"></a>
<script>
    function oncheck(link, itemId)
    {
        //the UI effects are working correctly
        if ($(link).hasClass("notchecked")
        {    
            $(link).fadeOut();
            $(link).removeClass("notchecked");
            $(link).addClass("checked");
            $(link).fadeIn("slow");                
        }
        {
            $(link).fadeOut();
            $(link).removeClass("checked");
            $(link).addClass("notchecked");
            $(link).fadeIn("slow");                
        }

        //do ajax request using jquery
        //I don't really care about the results right now
        //This doesn't work though, it never hits my controller action
        $.get("Item/ChangeCheckedStatus", { itemId: itemId } );
    }
</script>

I've also tried doing this with Microsoft Ajax libraries

Example B:

<%=Ajax.ActionLink(" ", 
    "Item", 
    "ChangeCheckedStatus", 
    new { itemId = item.ID }, 
    new AjaxOptions { UpdateTargetId="bogusTarget", OnSuccess = "oncheck" }, 
    new { @class="notchecked" });
<script>
    function oncheck()
    {
        //the UI effects are not working correctly here
        if ($(this).hasClass("notchecked")
        {    
            $(this).fadeOut();
            $(this).removeClass("notchecked");
            $(this).addClass("checked");
            $(this).fadeIn("slow");                
        }
        {
            $(this).fadeOut();
            $(this).removeClass("checked");
            $(this).addClass("notchecked");
            $(this).fadeIn("slow");                
        }                        
    }
</script>

With the MS AJAX libraries, I get to the controller action, and the item gets updated, but then the jquery effects don't work.

Is there an easier way to do what I'm trying to accomplish or am I just missing something obvious here??

UPDATE This is what the controller action looks like:

public string ChangeCheckedStatus(long itemId)
{
    //do some stuff
    return "What is going on???";
}

Note: other actions in the controller work fine, it's just this one (which is the only one used via AJAX btw).

Upvotes: 2

Views: 992

Answers (5)

Craig Stuntz
Craig Stuntz

Reputation: 126547

When you call an action with AJAX, and determine that the action is never run (e.g., a breakpoint at the start of the action is never hit), then you should always look at the Net tab Firebug, or the response from the server in Fiddler. There are two things to examine, here:

  1. The URL that your JavaScript called, including query string parameters, and any information in a POSTed form.
  2. The MVC framework usually gives you informative messages about why it could not bind to a particular action, so look for this information and the response from the server.

Upvotes: 1

Andy Grout
Andy Grout

Reputation: 167

You should use the ajax method as suggested by daddywoodland. The success method will be called when the AJAX call is successful. However, the this reference will not refer to your link but the window instead. This is because by the time the success method is asynchronously called you're outside the scope of the original onclick handler and therefore the method is no longer owned by the link, hence this is no longer the link but reverts to the window. This was essentially the same problem as your Microsoft AJAX library example above.

The trick, then, is to declare the success method as a closure inside your onclick method and have that closure refer to the link. I've tested the code below and it works. I placed a breakpoint on the server side action and it was hit.

<script type="text/javascript" src="../../Scripts/jquery-1.2.6.js"></script>
<a href="#" onclick="onLinkClick(this, 44)" class="notchecked">Click here...</a>
<script type="text/javascript">
    // Standard onclick handler.
    function onLinkClick(link, itemId) {

        // the function called asynchronously when the AJAX works
        var onCheck = function() {
            if ($(link).hasClass("notchecked")) {
                $(link).fadeOut();
                $(link).removeClass("notchecked");
                $(link).addClass("checked");
                $(link).fadeIn("slow");
            }
            else {
                $(link).fadeOut();
                $(link).removeClass("checked");
                $(link).addClass("notchecked");
                $(link).fadeIn("slow");
            }
        }

        // do the AJAX
        $.ajax({
            type: 'GET',
            url: 'Item/ChangeCheckedStatus',
            dataType: 'html',
            data: { itemId: itemId },
            success: function(response) {
                onCheck();
            }
        });
    }
</script>

You should be able to copy and paste this. So let me know if it doesn't work.

Upvotes: 1

scottm
scottm

Reputation: 28703

Can you put a break point in the controller to make sure it's being called? Maybe a routing problem if not...

Upvotes: 0

daddywoodland
daddywoodland

Reputation: 1512

The jQuery $.ajax method allows you to react if the ajax call was successful. Run your animation once the call has succeeded.

$.ajax({
  type: 'GET',
  url: 'Item/ChangeCheckedStatus',
  dataType: 'html',
  data: { itemId: itemId },  
  success: function(response){
    if(response == "success") {
      onCheck();
    }
  }
});

 function onCheck() {
    if ($(this).hasClass("notchecked")
    {    
        $(this).fadeOut();
        $(this).removeClass("notchecked");
        $(this).addClass("checked");
        $(this).fadeIn("slow");                
    }
    {
        $(this).fadeOut();
        $(this).removeClass("checked");
        $(this).addClass("notchecked");
        $(this).fadeIn("slow");                
    }               
 }

Upvotes: 0

CitizenBane
CitizenBane

Reputation: 855

Try something like this:

 $.get('Item/ChangeCheckedStatus', { itemId: itemId } , 'html', function() {
    if ($(this).hasClass("notchecked")
    {    
        $(this).fadeOut();
        $(this).removeClass("notchecked");
        $(this).addClass("checked");
        $(this).fadeIn("slow");                
    }
    {
        $(this).fadeOut();
        $(this).removeClass("checked");
        $(this).addClass("notchecked");
        $(this).fadeIn("slow");                
    }               
 });

Upvotes: 0

Related Questions