Lars335
Lars335

Reputation: 1880

Dropdown in kendo UI grid

I need a drop down for a Kendo-UI grid, and came across this example: http://codepen.io/jordanilchev/pen/cnkih?editors=001

But in this example, both the key and the display text for the drop down are included in the data source of the grid as well, which seems very redundant. I looked at a similar example on Telerik's site, and it was the same there.

Here is the data source for the Type drop-down:

var types = [
    {
        "Type": "FB",
        "Name": "Facebook"
    },
    {
        "Type": "TW",
        "Name": "Twitter"
    },
    {
        "Type": "YT",
        "Name": "YouTube"
    },
    {
        "Type": "PI",
        "Name": "Pinterest"
    }
];

So far so good. But here is the data for the actual grid - notice how it also contains both Type and Name for every record:

var products = [{
   "ProductID": 1,
   "ProductName": "Chai",
   "Type": {
      "Type": "FB",
      "Name": "Facebook"
   }
}, {
   "ProductID": 2,
   "ProductName": "Chang",
   "Type": {
      "Type": "FB",
      "Name": "Facebook"
   }
}...

What I had expected is that only the Type would have to be in the data source of the grid - like this:

var products = [{
   "ProductID": 1,
   "ProductName": "Chai",
   "Type": "FB",
}, {
   "ProductID": 2,
   "ProductName": "Chang",
   "Type": "FB",
}...

Is there a way to use a drop-down in the Kendo UI grid without having to include both the key and the display text for every record in the data source of the grid? In other words, the grid would know to reference the datasource of the drop-down to get the display text for the cell.

Update 9/23/2014: The solution proposed by CodingWithSpike works fine when the datasource for the drop down is a hard-coded / local array, but I am having difficulties getting it to work when loading the data for the drop down from a server. The issue seems to be that the grid gets initialized before the data source for the drop down has been read.

To "simulate" an $http call to populate the data source, I use a setTimeout:

$(document).ready(function () {
  var categories = [];

  setTimeout(function() {
    categories = [{
      "value": 1,
      "text": "Beverages"
    },{
      "value": 2,
      "text": "Condiments"
    },{
      "value": 3,
      "text": "Confections"
    }];
    $('#grid').data('kendoGrid').dataSource.read(); // Just as a test, but not even this helps
    $('#grid').data('kendoGrid').refresh(); // Just as a test, but not even this helps
  }, 1000);

When the data is loaded as above (or via $http), the drop down fields now contain the value (id) instead of the text. Here is a plunker that shows this: http://plnkr.co/edit/DWaaHGVAS6YuDcqTXPL8?p=preview

Note that the real app is an AngularJs app, and I would rather not use some jQuery hack to wait until the drop down data is available and then create the grid element.

How do I get this working with data from a server?

Upvotes: 1

Views: 2144

Answers (2)

Lars335
Lars335

Reputation: 1880

I asked Telerik about this, and here is the solution they gave.

When the drop-down's data is available, use setOptions on the grid, like this (again, I use setTimeout instead of an Ajax call here, for simplicity):

setTimeout(function() {
  categories = [{
      "value": 1,
      "text": "Beverages"
  },{
      "value": 2,
      "text": "Condiments"
  },{
      "value": 3,
      "text": "Confections"
  }];
  var grid = $('#grid').data('kendoGrid');
  var cols = grid.columns;
  cols[1].values = categories;
  grid.setOptions({columns: cols}); 
  $('#grid').data('kendoGrid').refresh();
}, 200);

Also, autoBind: false is not needed.

Here is an updated plunker: http://plnkr.co/edit/ZjuK9wk3Zq80yA0LIIWg?p=preview

Upvotes: 0

CodingWithSpike
CodingWithSpike

Reputation: 43698

Take a look at the Kendo demo for "Foreign Key" columns. I think it is exactly what you want.

http://demos.telerik.com/kendo-ui/grid/foreignkeycolumn

They use a list of categories:

           var categories = [{
                "value": 1,
                "text": "Beverages"
            },{
                "value": 2,
                "text": "Condiments"
            },{
                "value": 3,
                "text": "Confections"
            },{
                "value": 4,
                "text": "Dairy Products"
            },{
                "value": 5,
                "text": "Grains/Cereals"
            },{
                "value": 6,
                "text": "Meat/Poultry"
            },{
                "value": 7,
                "text": "Produce"
            },{
                "value": 8,
                "text": "Seafood"
            }];

The demo is a little deceiving because their data for the grid contains the entire "Category":

var products = [{
    ProductID : 1,
    ProductName : "Chai",
    SupplierID : 1,
    CategoryID : 1,
    QuantityPerUnit : "10 boxes x 20 bags",
    UnitPrice : 18.0000,
    UnitsInStock : 39,
    UnitsOnOrder : 0,
    ReorderLevel : 10,
    Discontinued : false,
    Category : {
        CategoryID : 1,
        CategoryName : "Beverages",
        Description : "Soft drinks, coffees, teas, beers, and ales"
    }
}

However, if you look at the column definition:

{ field: "CategoryID", width: "200px", values: categories, title: "Category" },

The specified field is CategoryID not Category so the grid data item actually doesn't need to specify a "Category" property at all, and could just be:

var products = [{
    ProductID : 1,
    ProductName : "Chai",
    SupplierID : 1,
    CategoryID : 1,  // <-- this is the important part!
    QuantityPerUnit : "10 boxes x 20 bags",
    UnitPrice : 18.0000,
    UnitsInStock : 39,
    UnitsOnOrder : 0,
    ReorderLevel : 10,
    Discontinued : false
}

I suspect the "Category" was in there just because this JSON file is shared by a few examples, so a different one may have needed it.


Update

Regarding the issue of the Grid loading before the "Category" (or whatever) FK table:

Use a deferred or the callback on the grid datasource to wait until the FK datasource is done loading before populating the grid data. Alternatively, you can init the grid, but set it to autoBind: false so that it doesn't actually read from its DataSource immediately.

Something like this (sorry for any errors, typing this off the top of my head):

(function () {
    // for the foreign keys
    var categoriesDataSource = new kendo.data.DataSource({
        transport: {
            read: {
                url: "http://somewhere.com/categories"
            }
        }
    });

    // for the actual grid data
    var gridDataSource = new kendo.data.DataSource({
        ...
    });

    // init the grid widget
    var gridWidget = $("#grid").kendoGrid({
        dataSource: gridDataSource,
        autoBind: false, // <-- don't read the DataSource. We will read it ourselves.
        columns: [ ... ]
    });

    // now we can read the FK table data.
    // when that completes, read the grid data.
    categoriesDataSource.fetch(function () {
        gridDataSource.fetch();
    });
});

Upvotes: 1

Related Questions