Creating AutoComplete Drop Down List using MVC Razor and Jquery

So I decided to get fancy with an old app today and put in some auto complete text boxes.  As usual I am using MVC and C# to do this along with JQuery.  The general idea is your view (html) is going to have a text box your value goes in.  Using Jquery.UI, you can call the autocomplete function on the textbox which does the magic for you.  Of course you need to create a server side json service to feed the autocomplete function's ajax request, but that's easy in MVC, lets take a look.
There are only really 3 parts of this functionality other than the includes of JQuery and JQuery.UI.  

The first is the textbox you want populated.  In this case I was making a vendor auto-complete drop down list and I wanted my form to be bound to it so I can take advantage of all the MVC goodness and not have to search for values later.  What I did was bind my SearchVendorId to a hidden field so when the page posts back later, I will get it.  The second line is the text box itself.  Nothing to fancy yet.
@Html.HiddenFor(model => model.SearchVendorId)
<input type="text" id="vendorsearch" placeholder="Search For Vendor" />
Next, I create the JQuery function that will turn that ordinary textbox into an awesome autocomplete box.  I actually split this in two pieces, the first is function that runs on the change event of the text box so I can clear the stored hidden value to 0 if the user changes it after the select and I change how the text box looks to let the user know it is a valid vendor or not using CSS.  The actual autocomplete function on the textbox first takes in the ajax call to make, and the success piece stores the results of label and value for the autocomplete function's inner implementation to render to the user.  Simple really.  All we have to do now is create that service.

$("#vendorsearch").change(function () {
            $('#SearchVendorId').val(0);
            if ($('#vendorsearch').val() != "") {
                $('#vendorsearch').addClass("errorTextBox");
                $('#vendorsearch').removeClass("successTextBox");
            }
            else {
                $('#vendorsearch').removeClass("successTextBox");
                $('#vendorsearch').removeClass("errorTextBox");
            }
        });
       $('#vendorsearch').autocomplete({
        source: function (request, response) {
            $.ajax({
                url: '@Url.Action("GetVendors")',
                data: { term: request.term },
                dataType: 'json',
                type: 'GET',
                contentType: "application/json; charset=utf-8",
                dataFilter: function(data) { return data; },
                success: function (data) {
                    response($.map(data, function (item) {
                        return {
                            label: item.label,
                            value: item.id
                        }
                    }));
                },
            })
        }
Finally, I create the JSON service that my JQuery calls.  Its a simple JsonResult function on my controller that takes in a term and does a quick query using Linq to SQL to get my vendor and returns a new object that matches the id, label, value model the autocomplete function looks for.  Slam that back with the Json function and your good to go.  Enjoy!
[HttpGet]
        public JsonResult GetVendors(string term = "")
        {
            var ctx = new PPMRK_VendiscDataDataContext();
            var returner = (from a in ctx.Vendor
                   where a.Name.ToUpper().Contains(term.ToUpper().Trim())
                   select new { id = a.VendorNumber, label = a.Name.Trim(), value = a.Name.Trim() })
                   .Take(20);
            return Json(returner, JsonRequestBehavior.AllowGet);
        }

String Or Binary Data would be truncated, Linq to SQL Entity Framework

So if you use Linq to SQL or the entity framework, no doubt you have run into the "String or Binary Data would be truncated error" at one point or another.  What is happening is simple, you are trying to insert a value into a SQL column that is longer than the column can hold so instead of trying it just fails. 
Usually this isn't a big deal as most systems and tables make it easy to see what you're doing wrong simply looking at the object you're saving.  In large system applications, it gets to be a bit of a chore and not as easy.  You basically need to compare the values on your object to ever filed in SQL until you find the culprit.  This is very manual.  
After fighting with this for half an hour today with no luck, I decided that the software knows what is wrong, we just need to have it tell us, so I wrote the following routine that uses reflection to re curse the object I am saving and tell me what field isn't going to fit.  I simply called it right before my SubmitChanges and it told me exactly what the problem was, I wish I would have done this a while ago.

public static void FindLongStrings(object testObject)
        {
            foreach (System.Reflection.PropertyInfo propInfo in testObject.GetType().GetProperties())
            {
                foreach (System.Data.Linq.Mapping.ColumnAttribute attribute in propInfo.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), true))
                {
                    if (attribute.DbType.ToLower().Contains("varchar"))
                    {
                        string dbType = attribute.DbType.ToLower();
                        int numberStartIndex = dbType.IndexOf("varchar(") + 8;
                        int numberEndIndex = dbType.IndexOf(")", numberStartIndex);
                        string lengthString = dbType.Substring(numberStartIndex, (numberEndIndex - numberStartIndex));
                        int maxLength = 0;
                        int.TryParse(lengthString, out maxLength);

                        string currentValue = (string)propInfo.GetValue(testObject, null);

                        if (!string.IsNullOrEmpty(currentValue) && currentValue.Length > maxLength)
                            Console.WriteLine(testObject.GetType().Name + "." + propInfo.Name + " " + currentValue + " Max: " + maxLength);
                    }
                }
            }
        }

Creating Web API with MVC

Today I revised my Resource project and instead of having custom controllers to call, I tried to consolidate my functions to a Web API.  To do this, I added a new controller to my MVC project with a basic Web API type by right clicking the controllers folder, and selecting Add > Controller.  In the Add Controller dialog, I Named it my object type Controller (ResourceController) and chose "API controller with empty read/write actions" from the Template drop-down.  

This created the basic set of web API functions.  I then made the functions less generic and gave them actual types to return.  Here is the class as I have it implemented, my Resource object now has a web API!

public class ResourceController : ApiController
    {
        // GET api/resource
        public IEnumerable<ResourceModel> Get()
        {
            return DataBridge.GetAllResources();
        }

        // GET api/resource/5
        public ResourceModel Get(int id)
        {
            return DataBridge.GetResource(id);
        }

        // POST api/resource
        public void Post(ResourceModel model)
        {
            DataBridge.AddResource(model);
        }

        // PUT api/resource/5
        public void Put(int id, ResourceModel model)
        {
            model.Id = id;
            DataBridge.SaveResource(model);
        }

        // DELETE api/resource/5
        public void Delete(int id)
        {
            DataBridge.DeleteResource(id);
        }
    }

Calling Generic MVC Web API from JQuery

So now you have created a Web API with MVC like here and you want to call its functions from JQuery.  Here is how you do it.  
So In this code example, I will be showing you how to create a JQuery function that can call my resource API from the article linked above.  Here are 3 example functions.

function addResource(id) {
        jPrompt('Please enter the Resource Name:', 'Enter Name', 'Prompt Dialog', function (r) {
            if (r) {
                $.ajax({
                    type: "POST",
                    url: "@Url.Action("Resource","api")",
                    data: { ReportsTo: id, Name: r, PercentFullTime: 100, Type: 0 },
                    dataType: "json",
                    success: function (response) { location.reload(); },
                    error: function (xhr, ajaxOptions, thrownError) { alert(xhr.responseText); }
                });
            }
        });
    }
    function deleteResource(id) {
        jConfirm('Are you sure you want to delete this resource?', 'Confirmation Dialog', function (r) {
            if (r) {
                $.ajax({
                    type: "Delete",
                    url: "@Url.Action("Resource","api")" +  '/' + id,
                    success: function (response) { location.reload(); },
                    error: function (xhr, ajaxOptions, thrownError) { alert(xhr.responseText); }
                });
            }
        });
    }
    function getResource(id){
        $.getJSON(
                "@Url.Action("Resource","api")",
                {id: id},
                function (myData) {
                    $('#ClickedId').empty().append(myData.Id);
                    $('#ClickedName').empty().append(myData.Name);
                    $('#ClickedPercent').empty().append(myData.PercentFullTime);
                    $('#ClickedType').empty().append(myData.Type);
                    $('#ClickedReportsTo').empty().append(myData.ReportsTo);
            });
    }
So the first function calls the Post API call. It submits a new resource to be saved. All it does is prompt the user for the name of the resource, and then constructs an ajax call of type POST to the API's URL which I generate with the URL.Action function giving it the controller name and api as a shortcut to construct the URL correctly. After that I just construct the Resource object by giving it the attributes and values that need to be filled in. The Success function reloads the screen so you can see the update. I realize why not just have the server side do the work if I'm posting back, this is just an example, put your display changing logic here. The next function does the same thing with delete. It prompts and then constructs the ajax call. The type is now delete and I couldn't get the data element to construct the id correctly so I concatenated the id to the string, boo. If anyone knows why this doesn't work, I would love to know. Finally, the last function gets the resource with an id. I use the getJSON function because it hides a lot of the ugly of the ajax call. In this one, I give it the base URL again, but am able to use the data to pass id unlike the delete. I then parse the response by just using it as my object, boy that feels nice. There you have it, a WEB API you can expose, and then call in the JQuery right there in your app, no need to duplicate controller methods!

Creating Right Click Context Menu with JQuery in MFC

So on a tree view I created in an earlier post, I wanted to add the ability to right click an item and have a context menu with a few options for that item.  To do this, I had to learn some new jQuery that I will share here.  My tree had a list of people, the function I will display is how to delete one of the persons clicked through a context menu.  

The first thing to do is add the following js and css files to make this work.  They are the context menu, which relies on position, as well as the alert js which gives us some good prompt dialog.
@Scripts.Render("~/Scripts/jquery.ui.position.js")
        @Scripts.Render("~/Scripts/jquery.contextmenu.js")
        @Styles.Render("~/Scripts/jquery.contextmenu.css")
        @Scripts.Render("~/Scripts/jquery.alerts.js")
        @Styles.Render("~/Scripts/jquery.alerts.css")
Now that we have our libraries in place, we can begin creating the functions.  So I wrapped each item in my list in a div tag.  That div tag has an attribute of ref on it which I store my id in and it has the text inside of it and a class of type context-menu-one (in case we need multiple)
<div class="context-menu-one box menu-1" ref="3">
        <strong>Heath Isely</strong>
    </div>
So to create my context menu, I use the following jquery function.  It calls the contextMenu on my context-menu-one div tags when right clicked with two items, Add Sub and Delete. 
$(function () {
        $.contextMenu({
            selector: '.context-menu-one',
            callback: function (key, options) {
                //var m = "clicked: " + key + ' id:' + $(this).attr('ref');
                //alert(m);
                if (key == "Delete")
                    deleteResource($(this).attr('ref'));
                else if (key == "Add Sub")
                    addResource($(this).attr('ref'));
            },
            items: {
                "Add Sub": { name: "AddChild" },
                "Delete": { name: "Delete" }
            }
        });
});
So now we have a context menu popping up. If you examined it closely, you can also see the callback function is set and detects which item was selected using a simple if block. Inside there, I call other functions depending on the item selected and pass them the id of the item stored in the ref attribute on the div tag we discussed before. The delete function is included below. It simply prompts if you're sure you want to delete the resource. If they click yes, it goes ahead and uses the ajax method to post to my deleteResource function . If it succeeds, it reloads the page to show the updated list.
function deleteResource(id) {
        jConfirm('Are you sure you want to delete this resource?', 'Confirmation Dialog', function (r) {
            if (r) {
                $.ajax({
                    type: "POST",
                    url: "@Url.Action("deleteResource","Home")",
            data: { ListID: id },
            dataType: "json",
            success: function (response) { location.reload(); },
            error: function (xhr, ajaxOptions, thrownError) { alert(xhr.responseText); }
                 });
            }
        });       
    }
The final piece I will show is the function on the server side for the delete call. It does the delete to the database and then responds with a json success response.
[HttpPost]
        public ActionResult deleteResource(int ListID)
        {
            DataBridge.DeleteResource(ListID);
            return Json("result", "success");
        }