jQuery MVC Form Helper

http://www.sethjuarez.com/post/2008/07/30/JQuery-MVC-Form-Helper.aspx

Seth Juarez has a great blog post on using jQuery with MVC Form Helper.  I know I have been using the MVCContrib ‘Grid’ and love how it was implemented.

Seth uses the same technique to building an ajax form that using jQuery.  It’s a good study on how to build controls with asp.net mvc.

Thanks Seth!

 

(I hope this form helper becomes a part of the contrib…)

 

update:  Well, I thought I’d fiddle with this a bit, and I created an override on the Helper and the Form object:

public static void JQueryForm<T, TController>(this HtmlHelper helper,
            string name, string onRequest, string onResponse, Expression<Action<TController>> editAction,
            T data,
            Action<T> block)
            where T : class
            where TController : Controller
        {
            Form f = new Form(name, onRequest, onResponse, helper.BuildUrlFromExpression<TController>(editAction),
                helper.ViewContext.HttpContext);
            f.RenderOpenWithRequestResponse();
            block.Invoke(data);
            f.RenderClose();
        }

I added an ‘onRequest’ and ‘onResponse’ so I could uniquely handle my own ajax callbacks.  I added a div with id of ‘Test’ and then the following javascript:

function onRequest(){
        $("#Test").html("Sending Data");
        alert('sending');
    }

    function onResponse(res){
        $("#Test").html(res).show();
    }

Then lastly, my changes to his Form class:

public Form(string name, string onRequest, string onResponse, string editAction, HttpContextBase context)
        {
            _name = name;
            _onRequest = onRequest;
            _onResponse = onResponse;
            _context = context;
            _editAction = editAction;
        }

added the onRequest – onResponse

Then a new constant:

private const string JS_ACTIONRESREQ = "var formData=$(this).serializeArray();$.ajax({{type:'POST',contentType:'application/x-www-form-urlencoded',url:'{0}',data:formData,dataType:'json',beforeSend:{1}, success:{2}}});return false;";
        

 

This adds ‘beforeSend’ and ‘success’, then lastly I created a new method:

public void RenderOpenWithRequestResponse()
        {
            string output = string.Format(FORM_OPEN, _name, string.Format(JS_ACTIONRESREQ, _editAction, _onRequest, _onResponse));
            _context.Response.Write(output);
        }

so, my form looks like this:

<%Html.JQueryForm<Car, HomeController>("carForm", "onRequest", "onResponse",
          c => c.AddCar(), null,
          s => {
            %>
                <div>Model: <%= Html.TextBox("Model") %></div>
                <div>Car: <%= Html.TextBox("Color") %></div>
                <div>Date: <%= Html.TextBox("Date") %></div>
                <div><%= Html.SubmitButton("Submit", "Submit") %></div>
            <%
          }
      );%>
      <div id="Test"></div>

(why the ‘null’ ?  Well, in his example, he is updating an item in his model.  Whereas, I’m ‘adding’ a new car.  Setting null worked, but I’m not sure of a better way – also – not always do I have a specific ‘Model’ object defined.  It appears to work if I just pass a ‘string’ – again though, I’m not sure of the best way to handle this senario)

 

Edit:

Not sure if this is correct or not, but I have been fiddling with this tonight (good stuff!)

 

First, the form:  updated to take a IDictionary of ‘ajaxOptions’

public Form(string name, AjaxDataType ajaxDataType, IDictionary ajaxOptions, HttpContextBase context)
public Form(string name, AjaxDataType ajaxDataType, IDictionary ajaxOptions, HttpContextBase context)
        {
            _context = context;
            StringBuilder ajaxAction = new StringBuilder("var formData=$(this).serializeArray();");
            ajaxAction.Append("$.ajax({type:'POST',contentType:'application/x-www-form-urlencoded',data:formData,");
            int counter = 0;
            ajaxAction.AppendFormat("dataType:'{0}'", ajaxDataType);
            if (ajaxOptions == null || ajaxOptions.Count > 0)
                ajaxAction.Append(",");
            foreach (DictionaryEntry option in ajaxOptions)
            {
                counter++;
                ajaxAction.AppendFormat("{0}:{1}", option.Key, option.Value);
                if(ajaxOptions.Count != counter)
                    ajaxAction.Append(",");

            }
            //"url:'{0}',data:formData,dataType:'json',beforeSend:{1}, success:{2}";

            ajaxAction.Append("});");
            ajaxAction.Append("return false;");

            AJAX_ACTION = string.Format(FORM_OPEN, name, ajaxAction.ToString());
        }
public void BeginRender()
        {
            _context.Response.Write(AJAX_ACTION);
        }

        public void RenderClose()
        {
            _context.Response.Write(FORM_CLOSE);
        }

the helper builds up the form:

public static void JQueryForm<T, TController>(this HtmlHelper helper,
            string name, AjaxDataType ajaxDataType, IDictionary ajaxOptions, Expression<Action<TController>> formAction,
            T data,
            Action<T> block)
            where T : class
            where TController : Controller
        {
            if (ajaxOptions == null)
                ajaxOptions = new Hash();
            ajaxOptions.Add("url", string.Format("'{0}'", helper.BuildUrlFromExpression<TController>(formAction)));
            Form f = new Form(name, ajaxDataType, ajaxOptions, helper.ViewContext.HttpContext);
            f.BeginRender();
            block.Invoke(data);
            f.RenderClose();
        }
 
Now, I use the MvcContrib Hash to pass a set of jquery ajax options to the jQueryForm.  (I did decide to create an enum for the dataType property)

<%Html.JQueryForm<string, HomeController>("carForm3", AjaxDataType.json, new MvcContrib.Hash(beforeSend => "onRequest", success => "onResponse"),
          c => c.AddCar(), null,
          s =>
          {
            %>
            <div>
                Model:
                <%= Html.TextBox("Model")%></div>
            <div>
                Car:
                <%= Html.TextBox("Color")%></div>
            <div>
                Date:
                <%= Html.TextBox("Date")%></div>
            <div>
                <%= Html.SubmitButton("Submit", "Submit")%></div>
            <%
          }
      );%>

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s