Asp.net MVC more Form post scenarios and Ajax

In the flickr explorer app made with Asp.net MVC and Athena, I was trying out some form post scenarios. In this post, I will add few things regarding MVC form post and Ajax that is common to FlickrXplorer but can be used in general.

Now, Asp.net MVC has some new Ajax features, one of this is the Ajax form post. With this, you can easily make your web app actions Ajax enabled. The syntax is pretty simple.

<% using (Ajax.Form("AddComment", "Comment", new AjaxOptions { UpdateTargetId = "cmContainer", 
           OnBegin = @"function(sender, args) {
                $get('caWait').style.display = 'block';
           }", 
           OnSuccess = @"function(sender, args) {
             $get('caWait').style.display = 'none';
           }", 
          }))
                            
       { %>

...
...

<% } %>

The piece of snippet is taken from FlickrXplorer : CommentsControl.ascx where I used MVC Ajax to do comment posts. Here you can see that I can pass in the UpdateTargetId , where the output of ContentResult or  if it is ViewResult, it will contain the rendered html for it. Additionally, there is OnBegin and OnSuccess events where I can do things like show or hide the wait panel and any other things I might like to do.

On the client code , probably in your default.master you need to have the following references to make things work.

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

Now, this is one way of doing things out. This basically injects the Ajax script in onsubmit of the html form where the actual magic happens. Now, this is not the only way, you might need to do custom tasks before the submission takes place, like check if the user has written something before pressing the submit button or selected his country dropdown before pressing checkout in an air-ticket inventory system. For this kind of issue,  here is another cool way that it can be done.

function doAjaxSubmit(form, e, waitPanelId, targetToUpdate, methodName) {
    
    var isValid = true;
    
    if (typeof methodName != 'undefined')
    {
        var validate = Function.createDelegate(this, methodName)    
        isValid = validate(form, null);
    }

    if (isValid) {

        if (e == null) return false;
        
        Sys.Mvc.AsyncForm.handleSubmit(form, new Sys.UI.DomEvent(e),
        {
            insertionMode: Sys.Mvc.InsertionMode.replace,
            updateTargetId: targetToUpdate,
            onBegin: Function.createDelegate(form, function(sender, args) {
                $get(waitPanelId).style.display = 'block';
            }),
            onSuccess:
            Function.createDelegate(form, function(sender, args) {
                $get(waitPanelId).style.display = 'none';
            })
        });

    }
    else {
        return false;
    }
}

So, I have written a tiny JS routine that is a similar script that Ajax.Form injects in onsubmit event of html form but with few changes. As, we can see that I need to pass the form instance (this), event (in this case submit), the target where the update will be pushed in and a delegate method if provided it will process the submit only if it passes the validation written by the implementer.

In the FlickrXplorer : CommentsControl.ascx i have modified previous the html block like

<% 
IDictionary<string, object> formParams = new Dictionary<string, object>();
formParams.Add("onsubmit", @"return doAjaxSubmit(this, event, 'caWait', 'cmContainer', function(sender, args) 
{
    return validateRequiredText('errComment', 'txtComment');
});");

using (Html.Form("Comment", "AddComment", Microsoft.Web.Mvc.FormMethod.Post, formParams))
                    
{ %>

<%= Html.Hidden("photoId", photoId) %>
...
...

<% 
} %>

In this case, I have converted the Ajax.Form to Html.Form, where I have hooked the onsubmit with doAjaxSubmit routine with few parameters. Inside the call back method, I have written the required logic for validating required field. So, if people lefts the comment textarea intentionally blank and tries to do a post he might see.

image 

Now, moving on to the next section, I would like to like see my pager do MVC form post but I would like to see a continue of parents parameters. Let's take the use case.

image

In other words, I need to delegate form action from parent to child. There are plenty of ways to do it. In my way, I have created a HtmlHelper extension method that prepares my child form with query params that come from the parent request.

public static string RenderRequiredFormPostElements(this HtmlHelper htmlHelper, string paramToExclude)
{
    string url = HttpContext.Current.Request.Path;

    StringBuilder builder = new StringBuilder();
    NameValueCollection queries = HttpContext.Current.Request.QueryString;

    foreach (string name in queries.AllKeys)
    {
        if (string.Compare(name, paramToExclude, true) == 0)
        {
            //skip
        }
        else
        {
            builder.Append(htmlHelper.Hidden(name, new {value = queries[name]}));
        }
    }
    return builder.ToString();
}

Here it renders html hidden elements based the current url, also I can pass in a particular query param (in this case "page") which I don't want to be processed. Finally, in the FlickrXplorer : Pager.ascx i have added the following lines

<form name="pagerForm" method="GET" action="<%= HttpContext.Current.Request.Path %>">

<%= Html.Hidden("page") %>         
<% = Html.RenderRequiredFormPostElements("page") %>             

...
...

Here, to include that  pager action is bound to the current url , which is in turn bound to an action in the controller class. Therefore, in this case Request.Path points to an action url /Photo/{action}  with paging value. Also, the possible action methods for which paging  value will be supplied need to handle the case if there is no paging.

That's all for now. All the example are shown here, ties to Asp.net MVC 5. You can find codes running at www.codeplex.com/flickrXplorer , please go to the source tab to grab the nightly build.

Enjoy !!!

kick it on DotNetKicks.com

No Comments