Kendo Grid "TypeError: u is undefined"

possible reason you may find this nondescript error

TypeError: u is undefined

I was getting this strange error while using KendoGrid which I had used many times before and I couldn't figure out why. I was simply calling:
$('#grid').kendoGrid();

On a simple table, nothing special. Turns out it was simply because I had used some <th> in the <tbody>, but it can only be located in the <thead>.

KendoUI : TypeError: n.slice is not a function

common error in Kendo UI that has a simple solution

The error:
TypeError: n.slice is not a function

Is not very clear, but it is pretty simple. You are generally using some sort of AutoComplete, DataGrid, etc. This simply means that you are not returning a collection (JSON), but a layer (or more) up from that collection you want to include. For example, you would be returning this JSON:
{
    "TrackingModels":[
        {"Id":17,"Name":"Bill"},
        {"Id":17,"Name":"Bob"}
    ]
}

When what Kendo is expecting is just this:
{[
    {"Id":17,"Name":"Bill"},
    {"Id":17,"Name":"Bob"}
]}

jQuery moveTo() plugin

simple way to move an element from A to B

Say you have these elements:
<ul id="A">
    <li id="L1">Stan</li>
    <li id="L2">Arnold</li>
</ul>
<ul id="B">
</ul>

And you want to move 'L1' (Stan) to ul 'B' - using this simple short plugin:
(function ($) {
    $.fn.moveTo = function (selector) {
        return this.each(function () {
            var element = $(this).detach();
            $(selector).append(element);
        });
    };
})(jQuery);

You can do that with this:
$('#L1').moveTo('#B');

Now you have this in your DOM:
<ul id="A">
    <li id="L2">Arnold</li>
</ul>
<ul id="B">
    <li id="L1">Stan</li>
</ul>

Or, similarly, you can do something like this:
$('li').moveTo('#B');

Now you have this in your DOM:
<ul id="A">
</ul>
<ul id="B">
    <li id="L1">Stan</li>
    <li id="L2">Arnold</li>
</ul>

Monitoring a DOM Element for Modification with jQuery

'watching' an element for any change within it

I recently ran into a situation where I had to modify a site that relied on an incredibly obfuscated and impossible to understand javascript file. I had to add in some elements after everything was populated with some function I didn't get, so I had to wait until a specific element was populated to do anything. Turns out the DOMNodeInserted event is what I needed:
var title = $("b.facility");
var title = $('#title');//the element I want to monitor
title.bind('DOMNodeInserted', function(e) {
    alert('element now contains: ' + $(e.target).html());
});

Pretty simple, but took me forever to figure out...

Inline AJAX DropDown and Text Editing with Asp.Net MVC and jQuery

including how to use a database to populate the dropdown

First thing is first, you will need to download jQuery and the Jeditable plugin (I prefer to refer to it as the Jedi-Table!). Be sure to put these references in your View (or Masterpage). Next, you have to set up a view on which to use an inline edit. I find that I often want to use this approach on tables of information. For this View, I will set it to use an IEnumerable of an Item I have called 'ItemOwner' (this is arbitrary and does not really matter). It will be a simple table that lists the Name and the Country of the owner, both of which will be editable inline. Here is the Index in my ExampleController.cs:
myDataContext db = new myDataContext();
public ActionResult Index()
{
    // get the info for the 'Countries' dropdown:
    ViewData["countries"] = db.Countries
        .Select(x => new SelectListItem() 
        { 
            Text = x.Name, 
            Value = x.Id.ToString() 
        }).ToJson();

    // get the 'ItemOwners' I am interested in:
    var owners = db.ItemOwners.Take(3);

    return View(owners);
}

As you can see there, I am also pulling the countries from the database and throwing them into the ViewState - we will get to this later. Since the Country is actually a foreign key relation, the value is set to an integer which is the identity field in the database. It is also using a .ToJson() extension which takes a IEnumerable<SelectListItem> and puts it into a simple JSON string that I use which is here:
public static string 
    ToJson(this IEnumerable<SelectListItem> slis)
{
    string output = "{";
    if (slis != null)
    {
        for (int i = 0; i < slis.Count(); i++)
        {    
            output += " '" + slis.Skip(i)
            .First().Value + "': '" + 
            slis.Skip(i).First().Text + "'" + 
            (i == slis.Count() - 1 ? " " : ",");
        }
    }
    return output += "}";
}

There is probably a better way to do that... but I don't know it?!

I am also pulling 3 ItemOwners from the database, I know this is silly, but it just an example. Here is how I am displaying them in the view:
<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Country</th>
        </tr>
    </thead>
    <tbody>
        <% foreach(var owner in Model) { %>
        <tr>
            <td><%= owner.Name %></td>
            <td><%= owner.Country.Abbreviation %></td>
        </tr>
        <% } %>
    </tbody>
</table>

Now that there is a simple table we want to make it a bit more interactive. Since we aregoing to make all of these fields editable, we need to add in a way to distinguish exactly what they are. To do that, we will need two things: the id of the item they are editing, and the type of inline editing we will be doing (i.e. dropdown or text input). So to do that, let's add in a few css classes and an identifieng ID:
<td id="name<%= owner.Id %>" class="editable text">
    <%= owner.Name %></td>
<td id="ctry<%= owner.Id %>" class="editable dropdown">
    <%= owner.Country.Abbreviation %></td>

And now add a little css to make them appear to be clickable:
td.editable:hover 
{ cursor:pointer; background-color:Orange; }

Now they all look like you can click on them, so we can move on to making the click actually do something.

This is where the jQuery comes in, and it is very simple. I have made these 'helper' methods in Javascript to make all of my inline calls centrally controllable, I keep this in my sites script folder so if I change one inline edit, I change them all; it also makes for more readable Javascript on each page.
function InlineDropdown(collectionToDropDown, ajaxAddress, dropDownDataSet) {
    collectionToDropDown.editable(ajaxAddress,
    {
        data: dropDownDataSet,
        type: 'select',
        indicator: 'saving...',
        tooltip: 'click to edit...',
        submit: 'Save',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextbox(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress, 
    {
        indicator: 'saving...',
        tooltip: 'click to edit...',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextarea(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress, 
    {
        type        : 'textarea',
        rows        : 4,
        indicator   : 'saving...',
        tooltip     : 'click to edit...',
        style       : 'inherit',
        submit      : 'Save',
        onblur      : 'ignore',
        placeholder : 'click to edit'
    });
}

Obviously you can read all about the options on the Jeditable page, but this is how I set them. Also notice I have a InineTextarea included as well for a textarea which is not covered here but works the exact same.

Now the jQuery calls are almost trivial:
InlineTextbox(
    $('td.editable.text'), 
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>"
);

InlineDropdown(
    $('td.editable.dropdown'), 
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>", 
    <%= ViewData["countries"].ToString() %>
);

What that is doing is sending the POST requests to the specified address. The POST contains a few things:
  • id - the id of the element that sent the request
  • value - the new value passed by the element
We are also passing more information there - remember that we passed both the type of field to edit and the id of the ItemOwner to edit, ie [name837] which emans we want to edit the Name field of ItemOwner 837. So we simply set up an ashx handler (which we specified above) to do the dirty work:
public void ProcessRequest(HttpContext context)
{
    string newValue;
    try
    {
        myDataContext db = new myDataContext();
        string elementId = context.Request.Form["id"];

        // since we made the first 4 of the id the 'field' whic to edit
        // we can just pull the first 4 letters for use in our switch:
        string fieldToEdit = elementId.Substring(0, 4);

        //now take anything after those 4 and it is the Id:
        int idToEdit = Convert.ToInt32(elementId.Remove(0, 4));

        // the value is simply a string:
        newValue = context.Request.Form["value"].Trim();

        // now that we have the id, get the ItemOwner from the db
        ItemOwner owner = db.ItemOwners.FirstOrDefault(x => x.Id == idToEdit);

        // after all is said and done, we will return newValue to the user so the field
        // looks as if the change has taken place (which it has)

        // using the field we pulled above, decide what to do:
        switch (fieldToEdit)
        {
            // name is easy
            case "name": owner.Name = newValue; break;

            // since the country is an integer foreign key, we need to Convert.ToInt32:
            case "ctry":
                owner.CountryId = Convert.ToInt32(newValue);
                // now that we have recorded the value, we want to return the text to
                // the user and not the id value which would make no sense
                newValue = db.Countries.FirstOrDefault(x => x.Id == owner.CountryId).Abbreviation;
                break;
            // if it wasn't caught, something is wrong:
            default: throw new Exception("invalid fieldToEdit passed");
        }

        db.SubmitChanges(); // save it
    }
    // now if an exceptions were reported, the user can see what happened
    // this also inform the user nothing was saved
    // you could easily make this not reported to the user and logged elsewhere
    catch (Exception ex) 
    { newValue = "Error: " + ex.Message + " [nothing written to db]"; }

    //now return what you want in the element:
    context.Response.Write(newValue);       
}

And that is all it takes.

Automatically refresh your user's Session behind the scenes using jQuery and Asp.Net

Incredibly simple script will keep your user's Session alive without any worries

Now this is something that may or may not be useful to a lot of people, depending on you situation, you may want the user to elect to refresh their Session or not (like banks usually do); but this is for applications that may have a lot of idle time and users are annoyed with their Sessions dying... considering most users don't know what a Session is, but they know that the application stops working correctly.

It uses jQuery and is incredibly simple, just a few lines of code, and no screen flicker or any annoyance to the user at all; ignorance is bliss. First I include the following in the code-behind in any page you need to keep refreshed (works on masterpages as well):

code-behind
protected int timeout;
protected void Page_Load(object sender, EventArgs e)
{
    // one minute prior to timeout (milliseconds)
    timeout = (Session.Timeout * 60000) - 60000; 
}

Then add this jQuery to your script:

aspx or master
var to;
$().ready(function() {
  to = setTimeout("TimedOut()", <%= timeout %> );
});
            
function TimedOut() {
  $.post( "refresh_session.aspx", null,
    function(data) { 
      if(data == "success") {
        to = setTimeout("TimedOut()", <%= timeout %>);
      }
      else { $("#timeout").slideDown('fast'); }
    }
  );
}

Notice that the jQuery calls the $.post() function, where it calls the page refresh_session.aspx. That page does only one thing: Response.Write("success"); so if data comes back and it does not equal 'success' (something went wrong) it then stops the cycle of checking for timeout and shows my 'timeout' div that tells the user it is not a current session.

infinitely refreshing session...

Yup, it is just that easy. The code-behind gets the Session.Timeout, and subtracts one minute from it, this is when the refresh will be triggered. Inside the script, the setTimeout() call will then wait that amount of time and use the jQuery $.post() to hit the page in in turn refresh the Session; once that is done, it starts the cycle over again, so it should repeat on into infinite. And since this is all done via a jQuery ajax call, there is no evidence to the user this is even happening, no flicker or popup, nothing.

Use jQuery to add all the values in a table column

simple way to get the total for a table

There are a lot of times when a table of data needs to be added up, or a summary provided; for Asp.Net users specifically, when you are using a dynamic GridView. Using jQuery, we can do this in just a few lines of code. If you don't care how it's done, skip to the bottom for a quick function to do the work for you. Here is a quick example:
nameageweightbenchpress
stan27177325
rj3013595
jose29230375

agesweightsbenchpresses
86542795

The first table is just a normal table holding the data, the second table is filled dynamically with jQuery adding up the columns. Yes, the numbers are real... RJ needs to hit the gym. Here is the jQuery to get these sums the manual way:
//these will hold the totals
var ages = 0;
var weights = 0;
var benchpresses = 0;

//reference the rows you want to add
//this will not include the header row
var rows = $("#data tr:gt(0)");
rows.children("td:nth-child(2)").each(function() {
    //each time we add the cell to the total
    ages += parseInt($(this).html());
});
rows.children("td:nth-child(3)").each(function() {
    weights += parseInt($(this).html());
});
rows.children("td:nth-child(4)").each(function() {
    benchpresses += parseInt($(this).html());
});

//then output them to the elements
$("#ages").html(ages);
$("#weights").html(weights);
$("#benchpresses").html(benchpresses);

First, I grabbed the table and each of it's rows; I also skipped the first row with the :gt() selector; I am grabbing all rows in #data (the id of the table with the data in it) greater than index '0' (the header that we don't want to include in the calculation). Also notice that I grabbed var rows = $("#data tr:gt(0)"); just once since we would be looping through it 3 times, there is no need to call it each time we sum a column; if I were just doing one column, I wouldn't use an extra line to place this into a var.

Next, I iterate through each cell using children() grabbing the correct index with :nth-child(); one thing I found strange was that though gt() started with a 0-based index, this uses a 1-based index.

Last, using the each() loop, I simply added the cell value to the total, then dumped them out to the cells I had reserved for the totals. All very simple and really only a few lines of jQuery to get it done.

function

If you don't really care how it works and just want a little snippet to get it to work, here you go:
function sumOfColumns(tableID, columnIndex, hasHeader) {
  var tot = 0;
  $("#" + tableID + " tr" + (hasHeader ? ":gt(0)" : ""))
  .children("td:nth-child(" + columnIndex + ")")
  .each(function() {
    tot += parseInt($(this).html());
  });
  return tot;
}

It takes in 3 arguments, and returns the sum of the columns:
  • tableID [string] id of the table
  • columnIndex [int] 1-based column index to sum up
  • hasHeader [bool] if the table has a header to exclude

The same thing above would be accomplished like this (though this is less efficient as jQuery is selcting the same table 3 times):
$("#ages").html(sumOfColumns("data", 2, true));
$("#weights").html(sumOfColumns("data", 3, true));
$("#benchpresses").html(sumOfColumns("data", 4, true));

As you can see, my function uses integers, so change it if you need to.

Inserting New Items Into a Table : 'REAL' AJAX with Asp.Net Series

Add a new item into the table and database and have it immediately sortable, pageable, etc without any postback

This is a continuation of my 'REAL' AJAX with Asp.Net (not Asp.Net AJAX) series posts for those of us trying to stop relying on Asp.Net 'AJAX'.

This is probably the hardest part about a full CRUD (Create, Read, Update, Delete) system, but as we have already covered 'RUD', it's time to hit the 'C'. First of all, we have to break down what will be happening, both on the client-side, and the server side, then it will be easier to dissect.
  1. User pulls up a 'New Entry' dialogue (client)
  2. User enters information and it is validated (client*)
  3. Valid information is sent to the server (client)
  4. Server attempts to add in new item (server)
  5. Server spits back status update (server)
  6. status update is displayed (client)
  7. item is added into the visible table (client)
  8. input fields are cleared and the input dialogue is hidden (client)

The * above denotes that while in this example we are doing only client-side validation, it is in your best interest to add in some server side as well (keep in mind that this example will not work without javascript, so it is not robust and does not 'gracefully' degrade).

As you can see, most of the heavy lifting here is done on the client side, with the dedicated server doing just a couple things.

set up the entry dialogue

First I am adding a couple divs which will be clicked to open the dialogue:

insert.aspx

<div class="button triggerNew">New Entry</div>


In the CSS, you can see that these will render like buttons:

demo.css
.button 
{ 
    width: 100px; 
    font-weight: bold; 
    border: outset 2px blue; 
    padding: 1px; 
    text-align: center; 
    color: Blue; 
}
.button:hover 
{ 
    border-style: inset; 
    cursor: pointer; 
    padding: 2px 0 0 2px; 
}

To go with the whole ajax feel, I am setting up the entry in a modal popup; you probably noticed the class 'triggerNew' which isn't really a css class, but it will be used to by jQuery to hook into any elements that have that class and tie them to the modal. To do that first we must include the jquery.jqModal plugin (which IMO is the best modal plugin as it is minimalist and customizable as well as easy to use) in our masterpage.
demo.master

<script type="text/javascript" src="js/jquery.jqModal.js"></script>


As for the modal popup, here is the markup:

<div class="jqmWindow" id="new">
  <h3 class="modal_header">
    <div class="working">working...</div>
    <a href="#" class="x jqmClose">X</a>
    Add New Entry
  </h3>
  <div class="pad">
    <div class="left">
      <h4>
        <asp:RequiredFieldValidator ID="rfvFirst" ControlToValidate="txtFirst" CssClass="right"
          ErrorMessage="required" runat="server" ValidationGroup="new" />
        First Name
      </h4>
      <input type="text" ID="txtFirst" runat="server" />
    </div>
    <div class="left">
      <h4>
        <asp:RequiredFieldValidator ID="rfvLasst" ControlToValidate="txtLast" CssClass="right"
          ErrorMessage="required" runat="server" ValidationGroup="new" />
        Last Name
      </h4>
      <input type="text" ID="txtLast" runat="server" />
    </div>
    <div class="left">
      <h4>
        <asp:RegularExpressionValidator ID="regAge" ControlToValidate="txtAge" CssClass="right"
          ErrorMessage="1-3 digits" runat="server" Display="dynamic" ValidationGroup="new" />
        <asp:RequiredFieldValidator ID="rfvAge" ControlToValidate="txtAge" CssClass="right"
          ErrorMessage="required" runat="server" Display="dynamic" ValidationGroup="new" />
        Age
      </h4>
      <input type="text" ID="txtAge" runat="server" />
    </div>
    <div class="summary">
      <div id="submit" class="button">Submit</div>
    </div>
  </div>
</div>


Now there is a lot going on there. First of all, I used the Asp.Net validators as we are most familiar with them, and they play nicely with jQuery. Also, I am not using asp:TextBoxes at all, I am sticking with the basic input boxes. But, because I am using the Asp.Net Validators, I still need to include runat="server" with each input that I Validate; this also means that they will get weird Asp.Net IDs and not the exact ones I assign them. All I am doing here is making sure all the fields have values, and that age is a diget with 1-3 digits (yes, someone can be 999 in this system...).

In addition, the css class 'jqmClose' class is included in a link: this will automatically be assigned to close the modal window by jqModal.

I also put an additional 'working' element in there so the user can see that dialogue while the program is running its magic.

But as it stands now, we can't even see that popup, get the validators to fire or submit any sort of data. Here comes the jQuery.

work the jQuery magic

Here is the script, it is explained in the comments:
//assign all 'triggerNew' elements to open the modal dialogue
$('#new').jqm({ trigger: false }).jqmAddTrigger($('.triggerNew'));

//attach this event to the clicking of the 'submit' div
$("#submit").click(function() {
    //will not do anything if the validators don't check out
    //Page_ClientValidate('ValidationGroup') is an Asp.Net generated function
    if (!Page_ClientValidate('new')) { return false; }
    else {
        // get the values from the textboxes into an array
        // notice that this is using .ClientID to get the strange Asp.Net ID assigned to it
        var vals = [
            $("#<%= txtFirst.ClientID %>"),
            $("#<%= txtLast.ClientID %>"),
            $("#<%= txtAge.ClientID %>")
        ];
        // do the ajax post
        $.post(
            //function is at
            "ajax_functions/insert.aspx",
            //send the values frorm the vals object
            { first: vals[0].val(), last: vals[1].val(), age: vals[2].val() },
            function(data) {
                //output the return data
                $("#report").html(data);
                // the class 'success' was sent back if it worked...
                var success = (data.toString().substring(12, 19) == "success");
                //add the new data into the table so the user can see it if it was successful
                if (success) {
                    oTable.fnAddData([
                    vals[0].val(),
                    vals[1].val(),
                    vals[2].val(),
                    '&nbsp;'
                ]);
                    //clear the textboxes
                    $(vals).each(function() { $(this).val('') });
                }
                //hide the modal now that it's done
                $('#new').jqmHide();
            }
        );
    }
});

Note that this will not allowed items added since the last postback to be deleted/edited, that is why the last cell simpy gets an '&nbsp;'. Keep in mind that it is possible, just beyond the scope of this tutorial.

Also, in a ghetto form of error reporting, I passed the css class which will either be 'error' on error, or 'success' otherwise.  We can use that to decide whether or not to post the new data into the table and to clear the inputs.  This will catch any errors that we did not already account for.

Really all that remains is the server-side part, we need to make the page that is called: "ajax_functions/insert.aspx" to handle the inputs passed.

server-side functions

Notice this time that we used a $.post() method, which sends the stated values and returns something - in this case, we are having it return a chunk of html which will tell us what happened with the server, and it will be pushed into the 'report' div. Here is our server operations:

ajax_functions/insert.aspx.cs
using System;

public partial class ajax_functions_insert : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        demoDataContext db = new demoDataContext();
        try
        {
            // get all the new values
            string first = Request.Form[0];
            string last = Request.Form[1];
            int age = Convert.ToInt32(Request.Form[2]);

            //make a new person
            person p = new person()
            {
                first_name = first,
                last_name = last,
                age = age
            };

            //insert them into the db
            db.persons.InsertOnSubmit(p);
            db.SubmitChanges();

            //if it was all successful
            Response.Write("<div class='success'>" + first + " " + last + " [" + age + "] inserted</div>");
        }
        // this will catch all the errors and output an error message if caught
        catch (Exception ex) 
        {
            Response.Write("<div class='success'>Error: " + ex.Message +"</div>");
        }
    }
}

As usual, this is the easy part. Now you have a full working CRUD system, with some pretty good error catching as such with absolutely no postbacks! Ajax is fun and can be quite useful, I hope these tutorials helped make it a little more accessible to some Asp.Net devs, I know I learned a lot making them.

« Deleting

Use and Manipulate Asp.Net Validators with jQuery and/or Javascript

Asp.Net has some great validation included - no need to learn new validation, just grab them with client-side scripting

The problem I found when going into jQuery validation, is that they mostly seem to assume that you can have more than one form on your page; which, for us Asp.Net devs, is not the case. After some digging, I figured out how to use the current validators which I am already familiar with (RegularExpressionValidator, RequiredFieldValidator, etc.) and just hook into them with javascript; no need to reinvent the wheel. It is very easy, and we don't lose the server-side validation that is so great with the Asp.Net validators (if you call on it that is).

want to make a certain validator(s) fire?

Let's say I have a RequiredFieldValidator named 'rfvFirst' and I want it to test for validation on the click event of the element with id 'some_link'. With jQuery, this is what I would do:
$("#some_link").click(function() {
    ValidatorValidate($("#<%= rfvFirst.ClientID %>")[0]);
});

Now, the ErrorMessage of 'rfvFirst' will show if it is not valid - it will behave just as if you tried to submit the form, but just for that validator itself. Notice that I am using <%= rfvFirst.ClientID %> which will pull the crazy Asp.Net id that is produced in Asp.net which is often something strange like 'ctl00_ContentPlaceHolder1_rfvFirst'.  Now, if you want to use a class or something else to select the Validators, that is fine too.  This will fire all of the Validators that have the CssClass 'fire':
$(".fire").each(function() {
    ValidatorValidate($(this)[0]);
});

want to have a button/link cause validation and only work if the page is valid?

For this, you need to make sure your validators each have a ValidationGroup set. In this example I am attaching it to a button with id 'submit' and the ValidationGroup 'new'. Simply attach the click event to Page_ClientValidate() method:
$("#submit").click(function() {
    return Page_ClientValidate('new');
});

This was the only method I found that actually returned something that could be used to tell if the page was valid (I am far from a JS pro). There is likely more ways to do this and I am interested in any that people have found!

want to stroll through the validators?

The are all held in an object (array) 'Page_Validators' and you can access it like any other array, looping or whatever. This will look through and output into the 'report' element the ids of all the Validators you have on your page:
for(var i=0,len=Page_Validators.length;i<len;++i){
    $("#report").append($(Page_Validators[i]).attr('id'));
    $("#report").append("<br />");
}

Finding web hosting reviews is the first step when you plan to build a website. It will help you ensure a great looking site.

Deleting Items From a Table : 'REAL' AJAX with Asp.Net Series

Delete an entry from the DB and remove the corresponding row from the table; plus an ajax loading indicator

This is a continuation of my 'REAL' AJAX with Asp.Net (not Asp.Net AJAX) series posts for those of us trying to stop relying on Asp.Net 'AJAX'.

GridView has an incredibly easy 'Delete' feature when used in conjunction with a DataSource, the problem is, that is requires a postback. Since we are going the ajax route, this is a no-go. Alternatively, we could wrap in in an UpdatePanel, but that is exactly what we are trying to avoid. Deleting is very easy, we use a lot of the same methods that were involved in fixing the sort on the last post and using the jQuery .ajax() method.

changes to the markup

First we have to add another column for deleting and stick a delete image in there, this is simple enough. I added unique ids to each row and each delete cell for jQuery to have something to hook on to, you could also add classes. The markup hasn't changed all too much:

delete.aspx

<asp:Repeater ID="rpt" runat="server" DataSourceID="lds">
  <HeaderTemplate>
    <table id="sort_table">
      <thead>
        <tr>
          <th>First</th><th>Last</th><th>Age</th><th></th>
        </tr>
      </thead>
      <tbody>
  </HeaderTemplate>
  <ItemTemplate>
    <tr>
      <td id="frst<%#Eval("person_id")%>" class="editable">
        <%#Eval("first_name")%>
      
</td>
      <td id="last<%#Eval("person_id")%>" class="editable">
        <%#Eval("last_name")%>
      
</td>
      <td id="age_<%#Eval("person_id")%>" class="editable">
        <%#Eval("age")%>
      
</td>
      <td style="test-align:right;" id="del_<%#Eval("person_id")%>">
        <img src="images/delete_item.png" alt="delete" />
      </td>
    </tr>
  </ItemTemplate>
  <FooterTemplate>
    </tbody></table>
  </FooterTemplate>
</asp:Repeater>
<asp:LinqDataSource ID="lds" runat="server"
  ContextTypeName="demoDataContext" TableName="persons" />


We put the id on the cell itself and not the image because it will be easier to grab with dataTables, not to mention easier to click.

now for the js

First of all, you will notice if we leave the .dataTables() call the same as before, you can now 'sort' by the last column (the delete column), that isn't right, we have to pass some parameters to our 'dataTables()' method to make sure that column gets ignored:
oTable = $("#sort_table").dataTable({
    "aoColumns": [null, null, null, { "bSortable": false}]
});

Also notice that we decided to store the resulting table in 'oTable' just like the last lesson. Remember that this is because the sortable data is not kept in the table itself, but in an associated array, which we will need later.

Now, using the same method as last time, we will grab the position of the clicked item, attempt the ajax call, but instead of changing a value, we will delete a row. Normally, deleting a row in ajax is very simple, you grab the row by the id, and do a hide() or slideUp(), etc. - but that will not totally work here. Sure it would function, but since we are using sizing and paging, they wouldn't reflect the changes: if you had 30 items in your table, and you were 'showing 10 of 30' items, and you deleted one the normal way, it would still say 'showing 10 of 30 items' when in fact, you are only now showing 9 of 29 items, and the problem then just compounds. The brilliant minds who wrote the dataTables plugin built in ways to get around this.

First thing, we get the position of the clicked item (which all have 'del_' as an id prefix) and store that:
var pos = oTable.fnGetPosition(this);

As well as the id of the cell as we need the corresponding 'person_id' that is contained there:
var del = $(this);

Then we simply call the .ajax() method in jQuery:
$.ajax({
    type: "POST",
    url: "ajax_functions/delete.aspx",
    data: "person_id=" + del.attr('id').replace('del_', ''),
    success: function() {
        $("#report").addClass("success").html("Person Deleted");
        oTable.fnDeleteRow(pos[0]);
    }
});

And that is where the magic happens. It was indicated that this was of type 'POST', the url that it is sent to (we will get to that in a moment), and the POST query that was sent (the delete cell's id, minus the 'del_' prefix). Then, on success, we simply output some feedback to the user into a new div with the id of 'report' - nothing special there. But on the next line, we use the 'oTable' that we stored earlier that has all of the sortable data, and call the included function 'fnDeleteRow' with the position that we collected earlier, and that is what deletes the row. The finished javascript looks like this:

delete.aspx
var oTable;
var aPos;
var editedCell;
$(function() {
    $("td[id^='del_']").addClass("pointer").click(function(event) {
        var pos = oTable.fnGetPosition(this);
        var del = $(this);
        $.ajax({
            type: "POST",
            url: "ajax_functions/delete.aspx",
            data: "person_id=" + del.attr('id').replace('del_', ''),
            success: function() {
                $("#report").addClass("success").html("Person Deleted");
                oTable.fnDeleteRow(pos[0]);
            }
        });
    });
    $(".editable").click(function() {
        aPos = oTable.fnGetPosition(this);
        editedCell = $(this);
    }).editInPlace({
        url: "ajax_functions/update.aspx",
        params: "ajax=yes",
        value_required: true,
        default_text: "click to edit",
        success: function() {
            var data = oTable.fnGetData(aPos[0]);
            data[aPos[1]] = editedCell.html();
        }
    });
    oTable = $("#sort_table").dataTable({
        "aoColumns": [null, null, null, { "bSortable": false}]
    });
});

backend

Lastly is the easy part, to make the backend to "ajax_functions/delete.aspx" to handle the POST.

ajax_functions/delete.aspx.cs
using System;
using System.Linq;

public partial class ajax_functions_delete : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        demoDataContext db = new demoDataContext();
        try
        {
            System.Threading.Thread.Sleep(1000);
            // get the person_id of the person being deleted
            int person_id = Convert.ToInt32(Request.Form[0]);
            db.persons.DeleteOnSubmit(db.persons.First(x => x.person_id == person_id));
            db.SubmitChanges();

            Response.Write("deleted");
        }
        // this will catch all the errors and output them to the edited field
        catch (Exception ex) { Response.Write("Error: " + ex.Message); }
    }
}

This code is pretty simple. Since we specified the POST in the ajax() call in jQuery, we knew the first element of the POST was going to be the person_id, and that is used to delete it from the DB.
*NOTE* that I used a Thread.Sleep() in there which I NEVER recommend using. it is just there to illustrate the ajax loading indicator that was implemented into the masterpage, which is covered next.

ajax loading indicator

I snuck a new div into the masterpage with the id of 'working' and bound it to all jQuery ajax events with the following js:
demo.master
$(function() {
    $("#working").bind("ajaxSend", function() {
        $(this).show();
    }).bind("ajaxComplete", function() {
        $(this).hide();
    });
});

Now any time jQuery is doing ajax, there will be a little notification so the user knows your app is not quitting on them. All other times, that div will be hidden.

Now all that we have left is the ability to add new items.