Adding a new column with contextual buttons to an ajax grid (KendoUI)

I recently had to add a new column to my KendoUI ajax grid which would have buttons representing actions possible on the row item based on the status of the row item. In my case, the row items were forms that were submitted which could have any of these actions possible: Approve/Reject/Remove/Create. This new column needed to have any combination of these buttons present based on the status of the row item and the role of the person viewing the list. So, an Approver could be looking at that list and see “Approve” and “Reject” buttons for newly submitted forms or no buttons at all for forms that have had an action (Approve/Reject) taken. Another role (Actor) could be viewing the list of form submissions and have “Create” present on forms that have been approved or “Remove” for forms that haven’t had any action taken. Simple enough, right?

Well, I started out using custom grid commands but it wasn’t the right solution for me because I needed the buttons to be present or absent based on the row object’s state. With the grid commands, the buttons would be present all the time. With the custom commands, it was trivial to get access to things like the row item ID and perform client-side validation. View an example of a custom command using JavaScript on Telerik’s website. I have a bare-bones version for MVC as a gist.

To add the new column to my ajax grid, I simply did this:

columns
    .Template(@<text></text>)
    .ClientTemplate(
    "# if (is_approved == 2) { #" +
        "<button onclick=\"clickMe('#=param1#','#=param2#');\">Approve</button>" + 
    "# } #"
    );

Where is_approved is an attribute of my Form object which I can now use to display which buttons when & where I want! Now this is pretty easy when you’re dealing with simple attributes in your object e.g. primitive datatypes like ints, strings, etc.

For part of my project, I needed to have the buttons clicks trigger an action based on the content of the one of the form object’s attributes which was a list of objects. With the custom command, it was as easy as accessing the name of the list of objects from the dataItem object [see below]

var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
//dataItem.object_list;

When I switched away from the custom command, I had to think of a new way to pass my list of objects as a parameter for the clickMe function referenced earlier and I instantly thought of making the list of objects into a JSON array! My plan was to add another attribute to my Form Object Data Transfer Object (DTO) which would be a string that could be parsed into JSON when received on the client.

To get started, I declared the ToString method in my Form Object DTO and wrote this:

public override string ToString(){
    return "[\\\'" + id + "\\\',\\\'"  + state + ""\\\']";
}

This ToString method when invoked would cause the object to be displayed as: [‘8′,’Approved’].sidenote: that’s not valid JSON but I did this to enable the string representation of the list of form objects to be displayed properly on the page.

Then, I created a list of strings where each element of the list would be the string representation of the form object and converted the list of strings to a massive string by using the String.Join method.

string massivestring = "[" + String.Join(",",objectList) + "]";

At this point, if I had a list containing 2 form objects, it would become a string that looked like this: [[‘4′,’New’],[‘5′,’Approved’]]. Again, this isn’t valid JSON but I did this to prevent parsing errors.

So, once clickMe got invoked (when the user clicks on the button), the string representation of the form objects was converted to a valid JSON string (inside the clickMe function) by replacing the single quotes with double quotes and I could do whatever I wanted to the JSON object.

function convertStringToJSON(str){
    var re = /'/g //the g makes the regex apply globally instead of just the first occurrence of the ' character
    var newStr = str.replace(re,"\"");
    try{
        var jsonResult = JSON.parse(newStr);
        return jsonResult;
    }catch(e){
        return JSON.parse("[]");
    }
} 

Hope this helps someone! Lord knows I’ve stood on the backs/research of others and I’m more than happy to do a little bit for someone else. Enjoy.

Advertisements