JQuery MVC Form Helper

Simple Form Helper

As I continue to use JQuery and MVC I am completely impressed with how much you can do with very little. I know the new preview 4 came out with an AjaxForm helper. I could not resist, so I made my own and added it to the whole controls project I've been working on. (I have not forgot about the grid, but I've gotten a little bored of it for the time being although I do want to finish it...). So here is the idea:

  1. Have complete control over HOW the form is rendered
  2. Be VERY light (I attached the whole thing to the onSubmit attribute on the form)
  3. Make it fast (it took me like a half an hour or so)

Using it

I found this nifty way of using an action delegate that "reads between the lines." The motivation came from the MVCContrib grids ability to completely define inline ASP.NET looking code and pass it into the helper. Here is how you use it (for some reason I find it useful to see how it works first, and then explain how it works):

   1:  <% Html.JQueryForm<Student, HomeController>("studentForm",
   2:         c => c.EditStudent(),
   3:         (ViewData.Model as IEnumerable<Student>).First<Student>(), 
   4:         s => 
   5:         { %>
   6:             <div><%= Html.TextBox("Id", s.Id.ToString()) %></div>
   7:             <div><%= Html.TextBox("FirstName", s.FirstName) %></div>
   8:             <div><%= Html.TextBox("LastName", s.LastName) %></div>
   9:             <div><%= Html.SubmitButton("Submit", "Submit") %></div>
  10:      <% }
  11:     ); 
  12:  %>

Parameter explanation:

  1. The name to give the form
  2. The action that should be invoked on the controller
  3. The POCO object that holds the data
  4. What to render (the Action delegate that says take a student S and make Html textboxes)

The types passed in are the POCO data object and the controller that will get the action.

Building it

I really just copied a lot of what I have already done with the grid (see previous posts) and made it more lightweight. First the helper:

   1:  public static void JQueryForm<T, TController>(this HtmlHelper helper, 
   2:      string name, Expression<Action<TController>> editAction, 
   3:      T data, 
   4:      Action<T> block) 
   5:      where T : class
   6:      where TController : Controller
   7:  {
   8:      Form f = new Form(name, 
   9:          helper.BuildUrlFromExpression<TController>(editAction), 
  10:          helper.ViewContext.HttpContext);
  11:      f.RenderOpen();
  12:      block.Invoke(data);
  13:      f.RenderClose();
  14:  }

Notice how simple it really is! Using the helper, I build a url from the controller expression, and then pass everything else into a Form object that only does 2 things: render the opening form tag, and render the closing form tag. The only catch is rendering the correct JavaScript code in the onSubmit attribute of the form tag. The rest was simple. Notice on line 4 above the delegate that takes the markup. This markup is rendered on line 11. For the "hard" part, I just copied the JQuery Ajax call from the Grid Control I have been working on. Here is the gist of it:

   1:  var formData = $(this).serializeArray();
   2:  $.ajax({
   3:        type : 'POST',
   4:        contentType : 'application/x-www-form-urlencoded',
   5:        url : 'edit ACTION here',
   6:        data : formData,
   7:        dataType : 'json',
   8:        success : function(msg){
   9:            alert('Complete! ('+msg+')')}
  10:       }
  11:   );
  12:  return false;

The return false is there to prevent the form from posting back.

Screenshot

Here are some screenshots of the whole thing:

The form rendered:

image

The postback:

image

Notice that I used the Request helper I built in a previous post. In order to do this, I am required to name the textboxes with the same name as the property of the object. This is how the helper resolves that appropriate attribute.

Code

Here is the code. You will find fragments of me starting to do the grid code as well.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

Upgrade to BlogEngine 1.4

Well, I finally upgraded to BlogEngine.NET 1.4 (patch and all). It took about 40 minutes or so (I was overly cautious of course). I am currently using SQL Server as the provider. Thanks to Al Nyveldt everything went smoothly. Overall, I like the widgets on the side. Everything else seems to be about the same (again I just finished installing). So far I like what I see!

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

MVC Form Helper

Moving away from ASP 3.0 Request.Form(" ...

As mentioned in my previous post, I wanted to find a way to auto-populate and entity object from the Request.Form collection. I also wanted (as an aside) to see if the grid still worked on MVC Preview 4 (it does). Here is the code:

   1:          public static T Request<T>(this Controller controller) where T : class, new()
   2:          {
   3:              T o = new T();
   4:              var request = controller.Request;
   5:              foreach (var property in typeof(T).GetProperties())
   6:              {
   7:                  // Check if the object has the appropriate property
   8:                  var q = (request.Form.AllKeys
   9:                      .Where<string>(s => s.ToLower() == property.Name.ToLower()))
  10:                      .ToList<string>();
  11:   
  12:                  // if more than one... ignore
  13:                  if(q.Count == 1)
  14:                  {
  15:                      string datum = request.Form[q[0]];
  16:                      if (property.PropertyType == typeof(string))
  17:                          property.SetValue(o, datum, null);
  18:                      else
  19:                          property.SetValue(o,
  20:                              Convert.ChangeType(datum, property.PropertyType),
  21:                              null);
  22:                  }
  23:              }
  24:   
  25:              return o;
  26:          }

Notice that this is not an extension on the HtmlHelper since this will only be used inside the controller (hence a controller extension method). Here is how it is used:

   1:  Student s = this.Request<Student>();

Now for the explanation! The constraints on T (line 1, the where part) say that T must be a reference type and have a parameter-less constructor. I guess it doesn't have to have a parameter-less constructor but I thought it would be a pain to find out which request key matched up with which parameter in the constructor. I also thought that Entity classes should be POCO objects so they would naturally have an empty constructor. Some screenshots:

Before:

image

After:

image

The Grid

I am continuing to work on the grid (this was a part of it). I just haven't gotten around to implementing the next thing all the way. The goal again was to have more control over how the grid should be rendered. I am borrowing some of the ideas from the MVCContrib grid but simplifying it a whole lot (for simple users like myself)

MVC Preview 4

I uninstalled preview 3 and then installed preview 4 and shortly after found that VS could not open my preview 3 stuff. Instead of rigging it, I just re-created the MVC part. The Controls assembly (the one with the grid) worked perfectly after correcting the references to the MVC dll's.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Ajax HTML Grid Control for ASP.NET MVC (Part 3)

Moving to an HTML Helper

As I was looking around at the various HTML helpers out there, I realized that I should probably conform and stick to what is being done. Having said that, I refactored the Grid class to be a new HTML helper. Here is how it is used (similar to an MvcForm<T> actually):

<% using (Html.GridControl<StudentController, StudentEntity, int>(
   s => s.EditStudent(), 
   s => s.DeleteStudent(), 
   ViewData.Model, 
   s => s.StudentId, 
   "Student",
   null)) {  %>
Special text here!
<% } %>

The GridControl has now been attached as an extension method to the standard HTML Helper. Doing that required a bit of re-arranging on the parameters that needed to be passed in to the helper. The first are the types being used:

  1. The first type is the Controller being used for updates
  2. The second is the type of item in the collection
  3. The last is the data type of the key of each item

For the parameters:

  1. The first specifies the controller action when an item is edited
  2. The second specifies the controller action when a item is deleted
  3. The third is the actual Collection object
  4. The fourth tells the GridControl how to generate the key for each item
  5. The fifth is the name to use for the control
  6. The last specifies any additional html attributes to use (not implemented currently)

I really liked using the action expressions since it allows a better granularity in handling the actual Ajax requests to the controller. I used the this code to generate the appropriate URLS (strings):

_editAction = helper.BuildUrlFromExpression<T>(editAction);
_deleteAction = helper.BuildUrlFromExpression<T>(deleteAction);

An important thing to note is that the grid is actually printed out when the helper is disposed. This means that anything that is placed inside of the using brackets will be shown before the grid is displayed.

grid

Getting Data to the Controller

Now for the actual work! The first thing I wanted to ensure was that I sent the data back to the controller via a POST and not a GET method. The $.getJSON function in JQuery performs a GET (see post) so I needed to change that. Here is what the grid produced for the save and delete actions:

else if(action == 'save')
{
    var arr = $('#Student_Form').serializeArray();
    $.ajax({
       type: 'POST',
       contentType: 'application/x-www-form-urlencoded',
       url: '/Student/EditStudent',
       data: arr,
       dataType: 'json',
       success: function(msg){
         alert( 'Data Saved: ' + msg );
       }
     });
}
else if(action == 'delete')
{
    var dat = 'DataId=' + id;
    $.ajax({
       type: 'POST',
       contentType: 'application/x-www-form-urlencoded',
       url: '/Student/DeleteStudent',
       data: dat,
       dataType: 'json',
       success: function(msg){
         alert( 'Delete: ' + msg );
       }
     });
}

Notice that this is a continuation of the JavaScript from the previous post. The fundamental JQuery call for AJAX is $.ajax(properties) where the properties are the specifications on how the AJAX call should be made. The first and most important thing was to use POST rather than GET. A GET http call is supposed to be idempotent while a POST call can actually change the state of the server. Both the delete and save actions should change the state of the server. Also, from a security standpoint, it is always easier to craft some form of URL to cause an action to execute on a controller when using GET. This can open things up to malicious attacks. Imagine anyone simply typing http://yoursite/Student/DeleteStudent?DataId=1232 into their browser and the controller deleting that record. That would be bad. With a POST this can be controlled better.

My favorite part of the JQuery code is the .serializeArray() part. This takes each of the valid form members and automagically places the data in a JSON array structure to be passed to the controller.

Getting the Data in the Controller

Here is a nice screenshot of what happens when the controller save action is fired:

postback

The AJAX postback, in conjunction with the .serializeArray() call placed all of the items of the StudentEntity in the Request.Form collection. Now for the ugly code (reminiscent of ASP 3.0)

    public JsonResult EditStudent()
    {
        StudentEntity student = new StudentEntity();
        student.StudentId = int.Parse(Request.Form["StudentId"]);
        student.Address = Request.Form["Address"];
        
        int age;
        if (int.TryParse(Request.Form["Age"], out age)) student.Age = age;
        student.FirstName = Request.Form["FirstName"];
        student.LastName = Request.Form["LastName"];
        student.Phone = Request.Form["Phone"];
        student.State = Request.Form["State"];
        student.Zip = Request.Form["Zip"];
        
        StudentService.SaveStudent(student);
        
        return new JsonResult
        {
           Data = "Edited student " + student.StudentId.ToString() + "!"
        };
    }

The result sent back is a simple message. More could be done here, but I have not thought about it too much. I also dislike the whole Request.Form["val"] stuff. I think this could be automated using the grid somehow so we can get rid of the tedious code. Actually I think adding a generic static method to the Grid class should do the trick. I will probably add it next time.

Things to do

So far things seem to be going well. Here are some things I would like to add:

  1. Better entity population from the Request.Form collection
  2. An "Add New" feature to the grid
  3. On delete of a row, remove the TR element from the table (the database thinks it is gone, but the HTML says otherwise)
  4. CSS Grid customization

If you can think of any other things drop me a line.

Code

The Code

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Ajax HTML Grid Control for ASP.NET MVC (Part 2)

Preamble

Over the long weekend I thought a lot about where I wanted to go with the grid "control" for ASP.NET MVC. One of the things that weighed heavily on my mind was the ability to have the control fully customizable. As I thought about this, I decided that first thing's first: I need to get the functionality working and then worry about the prettiness factor. So for those of you concerned about the customizability - it's coming. For now, I really want to focus on the ability of the grid to get work done.

Code Bloat

As I began to dive again into the previous code I realized that having everything in one extension method was going to be... well ugly. The first order of business was to abstract everything in to a separate DLL. In order to do so, I created a new Grid class that handles all of the grid drawing.

JavaScript

I am partial to using JQuery. So here is the general idea of what the JavaScript code needs to do:

  1. Detect that the user would like to edit a particular row
  2. Detect any rows previously being edited (to move the edit focus to the new row being edited)
  3. Display text boxes for the user to have the ability to edit the values
  4. Post back an edit or a delete

In order to do each of the items above, I needed to change what the grid was outputting a little. First I needed to wrap the table in a <form> tag in order to retrieve any valid values being edited. Also, I needed to add the following links: Edit, Delete, Cancel, Save. The first two (Edit, Delete) should be shown when a row was not in edit mode. The second two (Cancel, Save) should only be shown when a row is in edit mode. I also wanted to make sure that only one row was being edited at a time. Here is a fragment of the HTML the control produces:

<form name="Student_Form" id="Student_Form">
<table id="Student" style="border: solid 1px black;width:100%;">
<tr id="Student_6">
    <td class="edit">
    <span class="editor">
       <a id="6_Student_edit" href="#">Edit</a>&nbsp;
       <a id="6_Student_delete" href="#">Delete</a>
    </span>
    <span class="editing">
       <a id="6_Student_cancel" href="#">Cancel</a>&nbsp;
       <a id="6_Student_save" href="#">Save</a>
    </span></td><td class="StudentId">6</td>
    <td class="FirstName">Frances</td>
    <td class="LastName">Adams</td>
    <td class="Age">&nbsp;</td>
    <td class="Address">&nbsp;</td>
    <td class="City">&nbsp;</td>
    <td class="State">&nbsp;</td>
    <td class="Zip">&nbsp;</td>
    <td class="Phone">&nbsp;</td>
</tr>
...

Once I decided on the DOM elements the form would produce, it was time to put some JavaScript to each row. The first bit of code is designed to attach events to each of the links in the grid as well as hide the "editing" spans since each row by default starts in non-edit mode:

$('document').ready(
    function(){
        $('#Student span.editing').hide();
        $('#Student a').click(
            function(event){
                event.preventDefault();
                handleEditClick(this.id);
            }
        );
    }
);

This code ensures that the editing spans are hidden and each click event on the anchor tags are redirected to the handleEditClick function. Notice that I pass in the id of the actual anchor tag. These I defined as id_Grid_action (see above). Whenever a link is pushed I get those three pieces of information to proceed with processing. Now for the handleClick function (it is long):

function handleEditClick(itm) {
    var o = itm.split('_');
    var id = o[0];
    var grid = o[1];
    var action = o[2];
    var name = '#' + grid + '_' + id + ' td';

    if(action == 'edit')
    {
        // un-edit any others that might be in editmode
        $('#Student span.editor:hidden a:first').each(
            function() {
                var cl = this.id.split('_');
                $('#' + cl[0] + '_' + cl[1] + '_cancel').click();
            }
        );

        $('.editor', name).hide();
        $('.editing', name).show();

        $(name).each(
            function() {
                if($(this).hasClass('edit')) return;
                var data = $(this).text() == '&nbsp;' ? '' : $(this).text();
                $(this).html('<input type="text" name="' + $(this).attr('class') + 
'" value="' + data + '" size="10" />'); } ); } else if(action == 'cancel') { $('.editor', name).show(); $('.editing', name).hide(); $(name).each( function() { if($(this).hasClass('edit')) return; var data = $('input', this).val(); $(this).html(data == '' ? 'nbsp;' : data); } ); } else if(action == 'save') { //alert('Save ' + itm); var arr = $('#Student_Form').serializeArray(); $.each(arr, function(i, field) { alert(field.name + ': ' + field.value); } ); } else if(action == 'delete') alert('Delete ' + itm);

As advertised, I first break up the id_gird_action pair into variables that will be useful. Also notice that ALL actions come into this function. First lets focus on the edit action. Now this is why I love JQuery:

$('#Student span.editor:hidden a:first').each(...

This particular line of code selects the first anchor tag under a span with class editor that is hidden from the Student grid. Why would I want to do that? From the id of the anchor tag I can reconstruct the id of the cancel anchor tag and then "click" it in order to cancel the update. To do it any other way would be difficult (at least I think so). The elegance of JQuery allows for those kinds of things. Once we cancel any other edit, we proceed to go through each TD in the row in question (with the exception of the edit anchors) and push the data into text boxes. Also, we set the appropriate edit spans to visible and hidden in order to have the correct actions displayed. Next, the Cancel action. The job of the cancel action is to take the data out of the text boxes and stuff them back into the TD tag. I realize that I should probably add a "Do you want to save this?" confirm box, but I will leave that for later. Notice again the elegance of JQuery:

var data = $('input', this).val();

The $(INPUT, TD) functions as a selection within a previous selection. In other words, within the current TD, find me an INPUT HTML element and retrieve the value. Once we retrieve the value, we can put it back into the TD tag without the INPUT element.

The Grid Class

The first thing I did was write the JavaScript code with the output from the Grid class. In other words, I ran the flat table (without the JavaScript) and cut and pasted the table to a standard HTML file. Once I had the new HTML file I worked on the JavaScript until it worked as I expected. Now the only problem left was creating  a RenderJavaScript() that emitted the Grid specific JavaScript we needed. Doing that seemed a bit tedious so I downloaded a nifty little Add In that did it for me.

Outcome

Some screens:

image

Usage

Now that I've abstracted the Grid out to a completely separate project, I changed the helper class to this:

public static string ToAjaxGrid<T, TKey>(this IEnumerable<T> list, 
                                 Func<T, TKey> key, 
                                 string name)
{
   Grid<T, TKey> grid = new Grid<T,TKey>(list, key, name);
   return grid.Render();
}

This change allowed me to leave the code in the View the same:

<%= ViewData.Model.ToAjaxGrid<AjaxHelpers.Models.StudentEntity, int>(s => s.StudentId, "Student") %>

Next Time

I think the client side functionality is (mostly) done. For the next installment I will try to actually submit the requested actions to the MVC controller (save, delete).

Code

Download

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Ajax HTML Grid Control for ASP.NET MVC (Part 1)

At work we are starting a major project and I think we have decided to go the ASP.NET MVC route. One of the concerns we had was that we could not use traditional "web controls" (i.e. Telerik, DevExpress) since the all require the <...runat=server> portion. With that said, I thought I would start to take a look at how I would go about doing it! The first "control" I want to get off the ground is a data bound grid that allows asynchronous saves via JavaScript. We'll see how it goes!

Premise

The idea is to use an extension method to any IEnumerable<T> object that generates the grid. I also want to be able to use CSS to stylize any aspect of the grid. Additionally, there should be a way to edit (in place) any of the records in the grid and post the results back using AJAX. I think this should be an interesting project!

Code

For this part I just want to print out the stylized table. Here is the result:

public static string ToAjaxGrid<T, TKey>(this IEnumerable<T> list, 
                                 Func<T, TKey> key, 
                                 string name, 
                                 NameValueCollection attributes)
{
   string format = " style=\"{0}\"";
   StringBuilder sb = new StringBuilder();
   // Build outer table div
   sb.Append(String.Format("<table id=\"{0}\"{1}>\n", 
      name, 
      attributes["TableStyle"] != null 
         ? String.Format(format, attributes["TableStyle"]) : ""));
   foreach(T item in list)
   {
      // Build row div
      sb.Append(String.Format("<tr id=\"{0}_{1}\"{2}>\n\t", 
         name, key(item).ToString(), 
         attributes["RowStyle"] != null 
            ? String.Format(format, attributes["RowStyle"]) : ""));
         
      foreach(var property in typeof(T).GetProperties())
      {
         // Build row item span
         string span = "<td id=\"{0}_{1}\"{3}>{2}</td>";
         var itm = property.GetValue(item, new object[] { });
         itm = itm != null ? itm : "&nbsp;";
         sb.Append(String.Format(span, key(item), property.Name, itm, 
            attributes["ItemStyle"] != null 
               ? String.Format(format, attributes["ItemStyle"]) : ""));
      }
      sb.Append("\n</tr>\n");
   }
   sb.Append("\n</table>");
   return sb.ToString();
}

public static string ToAjaxGrid<T, TKey>(this IEnumerable<T> list, 
                              Func<T, TKey> key, 
                              string name)
{
   return list.ToAjaxGrid<T, TKey>(key, name, new NameValueCollection(0));
}

Before scratching your head and calling me names, let's see if I can 'splain what I did. The two methods are the same with the exception of the NameValueCollection. The idea behind the NameValueCollection is to be able to pass in the actual CSS styles for the Table, Row, and Item. Now for the nitty gritty. First the data types passed in generically: ToAjaxGrid<T, TKey>. The T represents the actual entity (or the rows) and the TKey represents the type of the primary key. I figured I would eventually need to know the primary key in later work. The "Func<T, TKey> key" paramter is a lambda that takes the T object and produces a TKey object. When iterating through the rows, it is important to somehow keep track of the primary key (at least I think it is). The name is the DOM identifier for the table that we will use later. So now the looping magic! It uses reflection to infer the properties of type T and then loops through each T in the IEnumerable<T> and then through each property in T. And we are done!

Usage

Here is a snippet of what it looked like when I used it:

<% var col = new NameValueCollection(); %>
<% col.Add("TableStyle", "border: solid 1px #000000; width: 100%"); %>
<% col.Add("ItemStyle", "border: solid 1px #00FF00; spacing: 5px"); %>
<%= ViewData.Model.ToAjaxGrid<StudentEntity, int>(s => s.StudentId, "students", col) %>

And what it looked like:

screen

Disclaimer

I have never done this before! If you think there is a smarter way, let me know so I can fix my stuff!

Currently rated 1.0 by 1 people

  • Currently 1/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Using JQuery to perform Ajax calls in ASP.NET MVC

As I was looking around for ways to enable Ajax in the current ASP.NET MVC release I found a couple of things that I found pretty useful and thought I should share.

The J in Ajax (JQuery)

The muscle behind the actual asynchronous calls comes from JavaScript. I looked around at a bunch of existing JavaScript libraries and settled on JQuery because of the way it leverages existing CSS knowledge. The three things that the library should do easily are:

  1. Help me easily display an "updater" to let user know something is happening (i.e. loading data),
  2. Assist in making the actual Ajax call without any hassle,
  3. and, most importantly, let me get 1 and 2 working without headaches.

Here is how JQuery helps in the three cases:

  1. The "updater":
    $('#updater').show();
    $('#updater').hide();
    Notice the way JQuery uses the standard CSS id selector. Could it be any easier?
  2. JQuery has the following Ajax calls available in its library:
    object.load( )
    $.get( )
    $.post( )
    $.getJSON( )
    This takes away (hides) all of the XmlHttp object nonsense from the whole Ajax call.
  3. See 1 and 2

ASP.NET MVC

There are tons of good posts/tutorials on exactly how the ASP.NET MVC model works so I will not attempt to get into it too much here. The most important thing to know is that there are three things working together:

  1. The Controller,
  2. The Model, and
  3. The View

The controller handles all of the requests, asks the model for data, and then instructs the view to present the data (if any) returned.

Routes

One of the neat things about the MVC framework is the notion of routes. The default route setup is as follows:

   1:  routes.MapRoute(
   2:          "Default",                                              // Route name
   3:          "{controller}/{action}/{id}",                           // URL with parameters
   4:          new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
   5:  );

This simply means that, from the root of your web app, whenever a URL of the form http://root/foo/baz/bar is presented, the routing engine will call the foo controller with the baz action while supplying it with the bar id.

Some Code

Enough explanation, now to some code!

The Model

Since this is not an exercise in using the database, I created a simple Model class for students:

   1:  public class Student
   2:  {
   3:     public string FirstName { get; set; }
   4:     public string LastName { get; set; }
   5:     public int StudentId { get; set; }
   6:          
   7:     public static IQueryable<Student> GetStudentDataList()
   8:     {
   9:        return new List<Student>() 
  10:        {
  11:           new Student { FirstName = "John", LastName = "Smith", StudentId = 1},
  12:           new Student { FirstName = "Susan", LastName = "Connor", StudentId = 2},
  13:           new Student { FirstName = "Bryan", LastName = "Jones", StudentId = 3},
  14:           new Student { FirstName = "Lucy", LastName = "Vargas", StudentId = 4},
  15:           new Student { FirstName = "Robert", LastName = "Jimenez", StudentId = 5},
  16:           new Student { FirstName = "Seth", LastName = "Juarez", StudentId = 6},
  17:           new Student { FirstName = "David", LastName = "Meeks", StudentId = 7},
  18:           new Student { FirstName = "Olivia", LastName = "Rassmusen", StudentId = 8},
  19:           new Student { FirstName = "Viola", LastName = "Masterson", StudentId = 9},
  20:           new Student { FirstName = "Russel", LastName = "Jones", StudentId = 10}
  21:        }
  22:        .AsQueryable<Student>();
  23:     }
  24:  }

This simply creates a new list of Students and returns them as an IQueryable.

The Controller

Since I want to only pass JSON serialized objects over the wire when making the Ajax calls, there is a handy return type for the action in the controller called JsonResult:

   1:  public JsonResult Find(string name)
   2:  {
   3:     // To simulate "wait"
   4:     System.Threading.Thread.Sleep(1500);
   5:          
   6:     return new JsonResult
   7:     {
   8:        Data = (from student in Student.GetStudentDataList()
   9:                where student.LastName.StartsWith(name)
  10:                select student).ToArray<Student>()
  11:     };
  12:  }

This will serialize the data out in the JSON format. Now for the actual interesting part:

The View

The html for this example is VERY simple:

   1:  <div id="query">
   2:        <%= Html.TextBox("textSearch") %>&nbsp;
   3:        <a href="#" id="linkFind">Find</a>&nbsp;&nbsp;&nbsp; 
   4:        <span class="update" id="updater">
   5:              <img src="<%= AppHelper.ImageUrl("indicator.gif") %>" alt="Loading" />
   6:              &nbsp;Loading...&nbsp;&nbsp;&nbsp;
   7:        </span>
   8:  </div>
   9:   <div class="label">Students:</div> 
  10:  <div id="studentList"></div>

There is a search box, a link, and update panel, and a div (studentList) that will be populated by the Ajax call. This is where the magic of the routing engine coupled with the JQuery Ajax call comes together:

 

   1:  $(document).ready(
   2:     function()
   3:     {
   4:        // Hide update box
   5:        $('#updater').hide();
   6:                  
   7:        var retrieveData = function(path,  query,  funStart,  funEnd, funHandleData)
   8:        {
   9:           // for displaying updater
  10:           funStart();
  11:                          
  12:           // retrieve JSON result
  13:           $.getJSON(
  14:              path,
  15:              { name : query },
  16:              function(data)
  17:              {
  18:                 // handle incoming data
  19:                 funHandleData(data);
  20:                 // for hiding updater
  21:                 funEnd();
  22:              }
  23:           );
  24:        };
  25:                  
  26:        // adding handling to find link
  27:        $('#linkFind').click(
  28:           function(event)
  29:           {
  30:              event.preventDefault();
  31:              retrieveData(
  32:                 // mvc route to JSON request
  33:                 '/Student/Find/', 
  34:                 // query from textbox
  35:                 $('#textSearch')[0].value, 
  36:                 // function to show updater
  37:                 function() { $('#updater').show(); }, 
  38:                 // function to hide updater
  39:                 function() { $('#updater').hide(); },
  40:                 // retrieving the data
  41:                 function(data)
  42:                 {
  43:                    // clear students (if any)
  44:                    $('#studentList > div').remove();
  45:                    // add students
  46:                    for(s in data)
  47:                    {
  48:                       var student = data[s];
  49:                       $('#studentList').append('<div>(' +  student.StudentId ... you get the idea                 
  50:                     }
  51:                 }
  52:              );
  53:            }
  54:         );
  55:      }
  56:  );

The retrieveData function uses the JQuery $.getJSON call to retrieve the data. It takes as arguments the path to the controller (remembering routes), the argument (in this case the query) that the controller action expects, as well as a couple of functions. These functions will handle the cases where the  request is started, the request is ended, and what to do with the data that is returned. Subsequently we add the event handler to the link that initiates the find request. Notice that we are passing in '/Student/Find/' as the path since we are using the Find action on the StudentController. The argument is passed in from the search text box. This sets into motion the asynchronous request to the controller. The controller then returns a JSON serialized array of Student objects. Once the data is received, the studentList div is then cleared and repopulated.

Screenshot

The request:

request

The response:

response

Conclusion

Hopefully this has been helpful! It was fun putting everything together. Feel free to send me an email or leave a comment on this post if there are any suggestions/comments.

Code

Currently rated 5.0 by 4 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

F# Dictionary Binary Search

During a recent assignment, I found the need to create a quick word lookup from an ordered dictionary file. I post the following:

   1: #light
   2: open System
   3: open System.IO
   4:  
   5: let rec line (s : StreamReader) (sawEol : bool) (acc : string) = 
   6:     match (char.ConvertFromUtf32(s.BaseStream.ReadByte())) with
   7:     | "\n" when (not sawEol) -> line s true ""
   8:     | "\n" when sawEol ->  acc
   9:     | str -> line s sawEol (acc + str)   
  10:  
  11: let rec binarySearch (s : StreamReader) (target : string) 
  12:                      (low : System.Int64) (high : System.Int64) =
  13:     let mid = Int64.shift_right (low + high) 1 in
  14:     let pos = s.BaseStream.Seek(mid, SeekOrigin.Begin) in 
  15:     let cur = (line s false "") in
  16:     printf "Current: %s\n" cur;
  17:     if (high < low) then
  18:         Int64.zero
  19:     elif (String.CompareOrdinal(cur, target) > 0) then
  20:         binarySearch s target low (mid - Int64.one)
  21:     elif (String.CompareOrdinal(cur, target) < 0) then
  22:         binarySearch s target (mid + Int64.one) high
  23:     else
  24:         mid
  25:  
  26: let isValidWordFromFile (filename: string) (word : string) =
  27:     let fileInfo = new FileInfo(filename) in
  28:     let size = fileInfo.Length in
  29:     use stream = fileInfo.OpenText() in
  30:     let res = (binarySearch stream word Int64.zero size) in
  31:     not (res = Int64.zero)
  32:  
  33: let output = isValidWordFromFile "dictionary.txt" "entropies";;
  34: printf "Found: %s\n" (any_to_string output);;
  35: Console.ReadKey();;

Let me describe what is happening. I have found that as I learn to write stuff functionally, I tend to do things from a top down approach but write it bottom up.  The isValidWordFromFile function simply gets everything set up. Note the use keyword in 

   1: use stream = fileInfo.OpenText() in

This is similar in nature to the using statement in C#: It ensures that the stream is disposed of after use. The two functions of interest are the binarySearch and line functions. The rec keyword makes both functions recursive in F#. The binarySearch function in essence keeps "halving" the dictionary file by seeing if the word is either a match, too "large" or too "small". If it is too large, it resumes the "halving" process but on the lower half of the file. If it is too small, it resumes the "halving" process on the upper half of the file.

When I originally started, I attempted to use the Stream.BaseStream.Seek method in conjunction with the Stream.ReadLine() in the binarySearch function. This was not functioning correctly. After calling Seek on the BaseStream, the current file position was set correctly. Calling Seek thereafter yielded no results. In comes the line method. I like this method because it truly shows the power of a functional language. It in essence takes a stream and spits out a complete line. Since it is possible that the file Position is in the middle of a line, it is important to actually retrieve the next complete line. The acc variable is an accumulator for each byte that is going to be the eventual string. The sawEol variable simply tells the function whether or not it saw an end of line character. The match construct takes the byte at the current position and sort of does a C# switch on it. I say sort of because this match construct is a lot more powerful than a simple switch. The first case is when it sees a "\n" AND has not seen an end of line character yet. This means that it is not yet time to start accumulating characters. If we see a "\n" AND have seen an end of line already, that means we have completely read an entire line. This essentially ends the recursion. If it is some other character, add it to the accumulator variable and keep going.

In summary, I am extremely impressed with the functional programming paradigm. It seems simpler when I'm finished with something useful. The problem I have been encountering is wrapping my imperative mind functionally.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: