KendoUI Context Menu: too cool!


Today KendoUI announced its new release KendoUI Professional Q2 2014 and during the video presentation they have shown the new Widget ContextMenu.

Despite of attending the presentation I did want to play with it and learn more about this Widget. What is the best way for quickly getting familiar with Kendo UI Widgets? Yes, you are right, their Demo web site but there is no demo about this widget, is that possible? Sure they will fix it pretty soon.

KendoUI Context Menu

What is a Context Menu? According Wiki definition:

A context menu (also called contextual, shortcut, and popup or pop-up menu) is a menu in a graphical user interface (GUI) that appears upon user interaction, such as a right-click mouse operation.

What is a ContextMenu for Kendo UI?

For Kendo UI is an HTML unordered list (pre) that might happen to have more than one level (another unordered list).

Something like:

<ul id="context-menu">
    <li>Option 1
        <ul>
            <li>Option 1.1</li>
            <li>Option 1.2</li>
            <li>Option 1.3
              <ul>
                <li>Option 1.3.1</li>
                <li>Option 1.3.2</li>
                <li>Option 1.3.3</li>
                <li>Option 1.3.4</li>
              </ul>
          	</li>
        </ul>
    </li>
    <li>Option 2
        <ul>
            <li>Option 2.1</li>
            <li>Option 2.2</li>
            <li>Option 2.3</li>
        </ul>
    </li>
</ul>

And this looks like:

KendoUI Context Menu
KendoUI Context Menu

Defining a ContextMenu

In the previous paragraphs I have shown how to define the content of the Context Menu but we should say which are the target elements on which this Context Menu is activated. To do so, you define in the initialization the target elements using a jQuery Selector.

Example:

$("#context-menu").kendoContextMenu({
    target: "#area1,#area2"
});

Here I define that the context menu is going to be displayed if you right-click on an HTML element which id is “area1” or “area2”. Any other part of your HTML will not display it.

Defining a ContextMenu as DataSource

Despite I’ve shown how to initialize the content of the Context Menu using an HTML unordered list (ul) you can also use a DataSource or an array as follow:

var ds = [
    {
        text: "Europe"
    },
    {
        text : "Americas",
        items: [
            {
                text : "North America",
                items: [
                    { text: "Canada" },
                    { text: "United States" },
                    { text: "Mexico" }
                ]
            },
            { text: "Central America" },
            {
                text : "South America",
                items: [
                    { text: "Argentina" },
                    { text: "Brazil" },
                    { text: "Chile" }
                ]
            }
        ]
    },
    {
        text: "Asia"
    }
];
$("

“).kendoContextMenu({ dataSource: ds, target: “#area1” });

KendoUI Context Menu using a DataSource
KendoUI Context Menu using a DataSource

Where each option is an entry in the array and nested option are nested elements stored in an array called “items”.

Since this context menu is actually not defined in HTML I’ve used “$(‘

‘).kendoContextMenu({…});” for creating an HTML element that will contain the menu.

Additional options for the menu items

I’ve shown how to just display a text but you can actually decorate the text using any HTML by doing:

    { text: "United States", encoded: false },

Here I’ve decorated the text as bold (b) and I have set “encoded” to “false” indicating that “<” and “>” should actually not be displayed as a character but being part of the HTML tag.

The following image shows what happen if I define the content of the context menu as:

...
    items: [
        { text: "Canada", encoded: true },
        { text: "United States", encoded: false },
        { text: "Mexico" }
    ]
...
KendoUI Context Menu using HTML codes
KendoUI Context Menu using HTML codes

You can also define a CSS class:

.ob-red {
    background : red;
}
.ob-green {
    background : green;
}
...
    items: [
        { text: "Argentina", cssClass: "ob-red" },
        { text: "Brazil" },
        { text: "Chile", cssClass: "ob-green" }
    ]
...
KendoUI Context Menu using cssClass
KendoUI Context Menu using cssClass

Or you can also add images using “spriteCssClass” or “imageUrl”:

.ob-flag-argentina {
    background-image: url(/images/flags/argentina.png);
}
...
    items: [
        { text: "Argentina", spriteCssClass: "ob-flag-argentina"  },
        { text: "Brazil", imageUrl: "/images/flags/brazil.png" },
        { text: "Chile" }
    ]

That looks like:

KendoUI Context Menu with images
KendoUI Context Menu with images

Reusing KendoUI Menu

The new Context Menu widget actually is pretty similar to Kendo UI Menu, it accepts most of the Menu options and the DataSource are reusable as well. This is how the Menu looks like if I use previous DataSource for defining a Menu.

KendoUI Menu
KendoUI Menu

KendoUI MultiSelect with server side filtering


Today I got a question where someone wanted to use KendoUI AutoComplete but wanted it to look like a KendoUI MultiSelect. When I wonder why he/she wanted to use an AutoComplete the only reason was because the list of elements was huge. So, why not using Server Side Filtering in a MultiSelect?.

KendoUI Server Side Filtering

When you need to manage a large list of elements the solution doing some filtering in the server and just transfer a few of them.

The advantages of this are multiple:

  1. Save bandwidth sending only few elements
  2. Do not render an HTML element for each element returned
  3. Save memory due to less DOM elements
  4. Save memory due to a smaller KendoUI DataSource
  5. Increase performance do to a smaller DOM

So why not always using Server Side Filtering? Sometimes the fact of going back and forth getting new elements is not worthy for a small list of elements and this increases the complexity in the server that needs to deal with filtering.

Think about the number of elements and how they are going to be displayed in screen, if there is no good reason for having all pre-loaded, try doing it in the server.

KendoUI MultiSelect with server side filtering: MySQL table structure

This example will show a KendoUI MultiSelect that allows to choose countries from a MySQL database.

The structure of the countries table in MySQL is:

mysql> desc countries;
+-------+---------------+------+-----+---------+-------+
| Field | Type          | Null | Key | Default | Extra |
+-------+---------------+------+-----+---------+-------+
| id    | decimal(10,0) | NO   | PRI | NULL    |       |
| name  | varchar(128)  | NO   |     | NULL    |       |
+-------+---------------+------+-----+---------+-------+
2 rows in set (0,00 sec)

mysql> 

And one sample of the content is:

mysql> select * from countries order by name limit 10;
+----+---------------------+
| id | name                |
+----+---------------------+
|  0 | Afghanistan         |
|  2 | Albania             |
|  3 | Algeria             |
|  4 | American Samoa      |
|  5 | Andorra             |
|  6 | Angola              |
|  7 | Anguilla            |
|  8 | Antarctica          |
|  9 | Antigua and Barbuda |
| 10 | Argentina           |
+----+---------------------+
10 rows in set (0,00 sec)

mysql> 

KendoUI MultiSelect with server side filtering: PHP select code

The PHP code for selecting the elements is:

<?php
// Create connection to the database 
// db server:  127.0.0.1 (localhost)
// db user: so
// db password : password
// db name : so
$con = mysqli_connect("127.0.0.1", "so", "password", "so");

// Initialize the list of countries to return
$countries = [];
// Check that we actually get a filter condition
if ($_GET && $_GET['filter']['filters'][0]) {
    // Get the value
    // NOTE: We are not checking other fields in filter since autocomplete will
    //       always send it as "starts with" and ignore case.
    $filter = $_GET['filter']['filters'][0]['value'];
    $where  = "where name like '" . $filter . "%' ";
}
else {
    // Did not get filter, do not build a where clause
    $where = "";
}
// Query MySQL and limit the list of results to 5
$result = mysqli_query($con, "SELECT name FROM countries " . $where . " order by 'name' limit 5");

// Build the array of results
while ($row = mysqli_fetch_array($result)) {
    array_push($countries, array("name" => $row['name']));
}
mysqli_close($con);

// Return it as JSON
header("Content-type: application/json");
echo json_encode($countries);
?>

KendoUI MultiSelect with server side filtering: JavaScript

And finally the MultiSelect definition:

// DataSource where the read URL is the PHP code above
var ds = new kendo.data.DataSource({
    transport      : {
        read: "select.php"
    },
    // Server Side Filtering
    serverFiltering: true
});

// MultiSelect Widget initialization
$("#items").kendoMultiSelect({
    dataValueField: "name",
    dataTextField : "name",
    dataSource    : ds
});

KendoUI DataSources + Dropbox DataStore: Create


After checking how to read data from Dropbox DataStore, update, and delete. It is time for creating new records.

Creating records into Dropbox DataStore from KendoUI Grid

Now, the important question to remember is that when KendoUI creates a record in a Grid, the value assigned to id is default value defined in the model, which typically is not defined and as consequence stays to null.

But, when the record is created in the server, it has to return an id not null to be used.

Grid modification for creating

What I am going to do is adding a button to the toolbar for creating a new record. Something like:

$("#grid").kendoGrid({
    dataSource: taskTableDS,
    editable  : "popup",
    toolbar   : ["create"],
    columns   : [
        { command: ["edit", "destroy"], width: 180 },
        { field: "taskname", width: 80 },
        { field: "created", format: "{0:G}", width: 200 },
        { field: "completed", width: 70 }
    ]
});

First step easy!

Add create method to transport

Now, the second step is adding the transport.create method that saves the data into Dropbox (using insert method) and informs KendoUI about the id of the newly created record.

create : function (op) {
    // Remove id to do not have it duplicated
    delete op.data.id;
    var record = taskTable.insert(op.data);
    op.success([record]);
}

It is important to note that KendoUI success will actually call schema.model.parse for converting record from Dropbox format into KendoUI format.

parse: function (d) {
        var res = [];
        $.each(d, function (idx, elem) {
            res.push(parseItem(elem));
        });
        return (res);
}

Now, the complete code of the example is:

// Insert your Dropbox app key here:
var DROPBOX_APP_KEY = '0sh............';

// Exposed for easy access in the browser console.
var client = new Dropbox.Client({key: DROPBOX_APP_KEY});
var taskTable = null;

// Try to finish OAuth authorization.
client.authenticate({interactive: true}, function (error) {
    if (error) {
        alert('Authentication error: ' + error);
    }
});

function parseItem(elem) {
    return {
        id       : elem.getId(),
        taskname : elem.get("taskname"),
        created  : elem.get("created"),
        completed: elem.get("completed")
    };
}

function readTasks(op) {
    if (client.isAuthenticated()) {
        // Client is authenticated. Display UI.
        var datastoreManager = client.getDatastoreManager();
        datastoreManager.openDefaultDatastore(function (error, datastore) {
            if (error) {
                alert('Error opening default datastore: ' + error);
            }
            taskTable = datastore.getTable('tasks');
            var records = taskTable.query();
            op.success(records);
        });
    }
}

var taskTableDS = new kendo.data.DataSource({
    transport: {
        read   : function (op) {
            readTasks(op);
        },
        update : function (op) {
            var data = op.data;
            var id = data.id;
            // Remove id to do not have it duplicated
            delete op.data.id;
            var record = taskTable.get(id).update(data);
            op.success([record]);
        },
        destroy: function (op) {
            taskTable.get(op.data.id).deleteRecord();
            op.success();
        },
        create : function (op) {
            // Remove id to do not have it duplicated
            delete op.data.id;
            var record = taskTable.insert(op.data);
            op.success([record]);
        }
    },
    schema   : {
        model: {
            id    : "id",
            fields: {
                id       : { type: "string" },
                taskname : { type: "string" },
                created  : { type: "date", editable: false },
                completed: { type: "boolean" }
            }
        },
        parse: function (d) {
            var res = [];
            $.each(d, function (idx, elem) {
                res.push(parseItem(elem));
            });
            return (res);
        }
    }
});

$("#grid").kendoGrid({
    dataSource: taskTableDS,
    editable  : "popup",
    toolbar   : ["create"],
    columns   : [
        { command: ["edit", "destroy"], width: 180 },
        { field: "taskname", width: 80 },
        { field: "created", format: "{0:G}", width: 200 },
        { field: "completed", width: 70 }
    ]
});

And the example looks like:

KendoUI DataSources + Dropbox DataStore: Delete


After seeing first how to read data from Dropbox DataStore into Kendo UI DataSource and then how to update it, now it is time for deleting records.

Deleting records from Dropbox DataStore

Start adding a delete button to the Grid.

$("#grid").kendoGrid({
    dataSource: taskTableDS,
    editable  : "inline",
    columns   : [
        { command: ["edit", "destroy"], width: 180 },
        { field: "taskname", width: 80 },
        { field: "created", format: "{0:G}", width: 200 },
        { field: "completed", width: 70 }
    ]
});

Deleting a record from DropBox is actually pretty simple, just invoke deleteRecord and it is gone! Then invoke success in Kendo UI side and also gone from Kendo UI DataSource.

So, my DataSource transport.destroy method is:

destroy: function (op) {
    taskTable.get(op.data.id).deleteRecord();
    op.success();
}

And the complete code is:

// Insert your Dropbox app key here:
var DROPBOX_APP_KEY = '0sh............';

// Exposed for easy access in the browser console.
var client = new Dropbox.Client({key: DROPBOX_APP_KEY});
var taskTable = null;

// Try to finish OAuth authorization.
client.authenticate({interactive: true}, function (error) {
    if (error) {
        alert('Authentication error: ' + error);
    }
});

function parseItem(elem) {
    return {
        id       : elem.getId(),
        taskname : elem.get("taskname"),
        created  : elem.get("created"),
        completed: elem.get("completed")
    };
}

function readTasks(op) {
    if (client.isAuthenticated()) {
        // Client is authenticated. Display UI.
        var datastoreManager = client.getDatastoreManager();
        datastoreManager.openDefaultDatastore(function (error, datastore) {
            if (error) {
                alert('Error opening default datastore: ' + error);
            }
            taskTable = datastore.getTable('tasks');
            var records = taskTable.query();
            op.success(records);
        });
    }
}

var taskTableDS = new kendo.data.DataSource({
    transport: {
        read   : function (op) {
            readTasks(op);
        },
        update : function (op) {
            var data = op.data;
            var id = data.id;
            // Remove id to do not have it duplicated
            delete op.data.id;
            var record = taskTable.get(id).update(data);
            op.success([record]);
        },
        destroy: function (op) {
            taskTable.get(op.data.id).deleteRecord();
            op.success();
        }
    },
    schema   : {
        model: {
            id    : "id",
            fields: {
                id       : { type: "string" },
                taskname : { type: "string" },
                created  : { type: "date", editable: false },
                completed: { type: "boolean" }
            }
        },
        parse: function (d) {
            var res = [];
            $.each(d, function (idx, elem) {
                res.push(parseItem(elem));
            });
            return (res);
        }
    }
});

$("#grid").kendoGrid({
    dataSource: taskTableDS,
    editable  : "popup",
    columns   : [
        { command: ["edit", "destroy"], width: 180 },
        { field: "taskname", width: 80 },
        { field: "created", format: "{0:G}", width: 200 },
        { field: "completed", width: 70 }
    ]
})

What I get is:

KendoUI Grid editing records when using rowTemplate: tips and tricks


I use to define templates for some columns of my Grid but sometimes I find more convenient using a rowTemplate.

It is not very likely that when using a rowTemplate you need to edit the record but … why not!

KendoUI grid with rowTemplate
KendoUI grid with rowTemplate

The question is that it is not trivial if you simply follow KendoUI examples.

KendoUI Grid: using a rowTemplate

Row Templates allows you to write some HTML used for displaying a record of your grid. This feature provides you the mechanism to make a row anything you want. Lets start defining a row for displaying the information.

<script id="rowTemplate" type="text/x-kendo-tmpl">
    <tr>
        <td class="photo">
            <img src="http://demos.kendoui.com/content/web/Employees/#:data.EmployeeID#.jpg"
                 alt="#: data.EmployeeID #"/>
        </td>
        <td class="details">
            <span class="title">#: Title #</span>
            <span class="description">Name : #: FirstName# #: LastName#</span>
            <span class="description">Country : #: Country# </span>
        </td>
        <td class="employeeID">
            #: EmployeeID #
        </td>
    </tr>
</script>

I define an HTML table row with 3 cells for displaying the Photo, Information about the Employee and the Employee Number. That looks like this:

KendoUI Grid using a three cell RowTemplate
KendoUI Grid using a three cell RowTemplate

And the code for initializing the Grid is:

$("#grid").kendoGrid({
    dataSource    : {
        type     : "odata",
        transport: {
            read: {
                url: "http://demos.kendoui.com/service/Northwind.svc/Employees"
            }
        }
    },
    rowTemplate   : kendo.template($("#rowTemplate").html()),
    height        : 430,
    columns       : [
        { title: "Picture", width: 140 },
        { title: "Details", width: 300 },
        { title: "ID" }
    ]
});

Just need to specify rowTemplate and KendoUI takes care of it and since we are binding more than one field to each column, we do not specify field but only the title.

Kendo UI Grid and Row Template: add edit button

If we want to add an edit button, the very first thing is getting creating an extra column for it both in the Grid definition:

$("#grid").kendoGrid({
    dataSource    : {
        type     : "odata",
        transport: {
            read: {
                url: "http://demos.kendoui.com/service/Northwind.svc/Employees"
            }
        }
    },
    rowTemplate   : kendo.template($("#rowTemplate").html()),
    height        : 430,
    columns       : [
        { title: "&nbsp;", width: 90 },
        { title: "Picture", width: 140 },
        { title: "Details", width: 300 },
        { title: "ID" }
    ]
});

and in the template:

<script id="rowTemplate" type="text/x-kendo-tmpl">
    <tr>
        <td>
            Edit
        </td>
        <td class="photo">
            <img src="http://demos.kendoui.com/content/web/Employees/#:data.EmployeeID#.jpg"
                 alt="#: data.EmployeeID #"/>
        </td>
        <td class="details">
            <span class="title">#: Title #</span>
            <span class="description">Name : #: FirstName# #: LastName#</span>
            <span class="description">Country : #: Country# </span>
        </td>
        <td class="employeeID">
            #: EmployeeID #
        </td>
    </tr>
</script>
KendoUI Grid with RowTemplate added column for edit button
KendoUI Grid with RowTemplate added column for edit button

But we want it to look like the regular KendoUI button, so we have to style it:

<td>
    <a class="k-button k-button-icontext k-grid-edit" href="\#">
        <span class="k-icon k-edit"></span>Edit
    </a>
</td>

And we have a perfect KendoUI button:

Styled Edit button
Styled Edit button

But if we click on it, it does not open the record. Actually even if we define a button that does something like:

$("#edit-first").on("click", function() {
    var grid = $("#grid").data("kendoGrid");
    grid.editRow($("tr:nth(1)", grid.tbody));
});

So, what happens! Just a little detail, we did not specify the uid of the row. We should have defined in our template the <tr> element as:

<script id="rowTemplate" type="text/x-kendo-tmpl">
    <tr data-uid="#= uid #">
        <td>
            <a class="k-button k-button-icontext k-grid-edit" href="\#">
                <span class="k-icon k-edit"></span>Edit
            </a>
        </td>
        <td class="photo">
            ...

This is explained in the documentation as:

The outermost HTML element in the template must be a table row (<tr>). That table row must have the uid data attribute set to #= uid #. The grid uses the uid data attribute to determine the data to which a table row is bound to.

But not used in the demos, so if we cut and paste code we end-up having that does not work.

So, problem solved!

KendoUI move rows between grids


One other post that comes from my experience in Stack Overflow…

This time I will explain something that is commonly used: have two grids side by side and move rows between them.

These typically look like this:

Original two gridsWhere you can select one or more rows in both grids:

Rows selectionAnd then click on a button for moving selected arrows resulting:

Rows moved

Obviously, you can select rows in the second grid and move them back to the first.

KendoUI: moving rows between grids

First, I will start defining a container for both grids and buttons. This would be something like:

<div id="panels">
    <div id="grid1"></div>
    <div id="commands">
        <div><a href="#" id="copySelectedToGrid2" class="k-button">&gt;</a></div>
        <div><a href="#" id="copySelectedToGrid1" class="k-button">&lt;</a></div>
    </div>
    <div id="grid2"></div>
</div>

And I need some CSS styling:

#panels { display: table-row; }
#grid1, #grid2 { width: 400px; display: table-cell; }
#commands { text-align: center; width: 50px; vertical-align: middle; display: table-cell; }
#commands div { padding: 5px; }
#commands div a { width: 35px; text-align: center; }

Then, I define the grids that are something like this:

var grid1 = $("#grid1").kendoGrid({
    dataSource: ds1,
    editable:   "popup",
    selectable: "multiple",
    pageable:   false,
    columns:    [
        { field: "FirstName", width: 90, title: "First Name" } ,
        { field: "LastName", width: 90, title: "Last Name" }
    ]
}).data("kendoGrid");

var grid2 = $("#grid2").kendoGrid({
    dataSource: ds2,
    editable:   "popup",
    selectable: "multiple",
    pageable:   false,
    columns:    [
        { field: "FirstName", width: 90, title: "First Name" } ,
        { field: "LastName", width: 90, title: "Last Name" }
    ]
}).data("kendoGrid");

The only remarkable question is that I’m allowing multiple selection and disabling pagination since I want visible all values of each of the grids (making easier see how rows move between grids).

Moving rows

The first part is defining the click event handler for the two buttons. This is something like:

$("#copySelectedToGrid2").on("click", function (idx, elem) {
    moveTo(grid1, grid2);
});
$("#copySelectedToGrid1").on("click", function (idx, elem) {
    moveTo(grid2, grid1);
});

And moveTo function is:

function moveTo(from, to) {
    var selected = from.select();
    if (selected.length > 0) {
        var items = [];
        $.each(selected, function (idx, elem) {
            items.push(from.dataItem(elem));
        });
        var fromDS = from.dataSource;
        var toDS = to.dataSource;
        $.each(items, function (idx, elem) {
            toDS.add($.extend({}, elem));
            fromDS.remove(elem);
        });
        toDS.sync();
        fromDS.sync();
    }
}

Where I get selected rows and iterate getting the items selected. The reason why I do it in two steps (get the data item and the insert into second grid and remove from the first grid) is because arrays are expected to immutable, which means: I cannot remove one element from an array while iterating on it since this alters the array not being able to correctly continue the iteration.

Finally, I invoke sync on both DataSources for sending the modification to the server.

Pretty easy, don’t think so!

If you want to see it running, there is a JSFiddle here.

KendoUI: readonly rows (how to and command template)


A couple days ago Piyush, a frequent reader and commenter on this blog, asked me about how to make a row in a KendoUI grid read-only.

What he tried was handling edit event and if the row was read-only then he exited the edit mode but this introduced and undesired effect: a flickering (due to entering and exiting edit popup/inline mode).

KendoUI: read-only rows

Flickering

What Piyush originally asked me was how to avoid flickering but this is actually not possible since by the time edit event is fired, the row is already in edit mode.

You can easily demonstrate this introducing and alert(“editing”); in the code and you see that the popup window for editing fields is active while alert window is waiting for ok so, you will always have the flickering.

Lets have the following DataSource definition:

var dataSource = new kendo.data.DataSource({
    data    : [
        { symbol: "AAPL", company: "Apple Inc.", readonly: true },
        { symbol: "AMZN", company: "Amazon.com Inc.", readonly: true },
        { symbol: "IBM", company: "International Business Machines Corp." },
        { symbol: "CSCO", company: "Amazon.com Inc", readonly: true },
        { symbol: "MSFT", company: "Microsoft Corp.", readonly:false },
        { symbol: "INTC", company: "Intel Corp." },
        { symbol: "QCOM", company: "QUALCOMM Inc." },
        { symbol: "ORCL", company: "Oracle Corp." },
        { symbol: "HPQ", company: "Hewlett-Packard Company" },
        { symbol: "CRM", company: "salesforce.com, Inc." }
    ],
    pageSize: 5
});

And the grid defined as:

var grid = $("#stocks_tbl").kendoGrid({
    dataSource: dataSource,
    columns   : [
        { command: "edit", width: 100 },
        { field: "symbol", title: "Symbol", width: 100 },
        { field: "company", title: "Company", width: 300 }
    ],
    editable  : "popup",
    edit      : function () {
        alert("editing");
        grid.closeCell();
    },
    pageable  : true
}).data("kendoGrid");

If you run this you will see:

Capture1

So, there is nothing that we can do for avoiding the flickering but there are some things that I can do for getting the desired result.

Template based solution

This solution is based on defining a template that creates an Edit button for each row but controlled by readonly field.

The template would be something like:

<script id="edit-template" type="text/x-kendo-template">
    # if (!data.readonly) { #
    <a class="k-button k-button-icontext k-grid-edit" href="\#"><span class="k-icon k-edit"></span>Edit</a>
    # } #
</script>

and the new JavaScript code:

var editTemplate = kendo.template($("#edit-template").html());
var grid = $("#stocks_tbl").kendoGrid({
    dataSource: dataSource,
    columns   : [
        { field: "readonly", title: "", width: 100, template: editTemplate },
        { field: "symbol", title: "Symbol", width: 100 },
        { field: "company", title: "Company", width: 300 }
    ],
    editable  : "popup",
    pageable  : true
}).data("kendoGrid");

And this looks like:

Capture2

Done! … Actually almost, if I click on Edit button, I get:

Capture3

Where the field readonly is editable.

I might try to define a Schema for the DataSource and define readonly as not editable. But this does not prevent the field from being rendered.

Capture4

What else may I try?

  1. Remove the title of the field by defining it to a white-space using title: “ “ (note that there is a blank between both “).
  2. Define an editor function that actually does nothing.

What I have now is:

var grid = $("#stocks_tbl").kendoGrid({
    dataSource: dataSource,
    columns   : [
        { field: "readonly", title: " ", width: 100, template: editTemplate, editor: function() {} },
        { field: "symbol", title: "Symbol", width: 100 },
        { field: "company", title: "Company", width: 300 }
    ],
    editable  : "popup",
    pageable  : true
}).data("kendoGrid");

And when I edit the field I finally get:

Screen Shot 2012-12-26 at 00.43.28