Overview:
In this third post on Kendo UI Wrapper for ASP.NET MVC, we will look at one more wrapper named ComboBox. If you are new to Kendo UI Wrappers for ASP.NET MVC, I suggest that you go through “Jumpstarting Development with Kendo UI for ASP.NET MVC” by Abhishek Kant. This post, as the name suggests will give you a jumpstart on Kendo UI Wrappers for ASP.NET MVC. Lets go ahead and look at the ComboBox Wrapper in detail. If you are looking for the index post on this getting started series, click here.
What is The ComboBox control?
The ComboBox control displays a list of values and allows the selection of a single value from this list. Custom values may also be entered via keyboard input. If you do not wish permit keyboard input – that is, custom values are not permitted – use the DropDownList.
The ComboBox represents a richer version of a <select>
element, providing support for local and remote data binding, item templates, and configurable options for controlling the list behavior.
Instantiating a ComboBox:
To instantiate a ComboBox on any page, we make use of the ComboBox builder available within the Kendo helper. See below the code snippet to instantiate a combobox:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: )
That’s it to get a combobox control on the page. Note that the Name is mandatory to be set on the wrapper. This makes the ID of the combobox when rendered on the client side. Here is the output of our code:
As you can see the combobox control is created on the page. But we don’t see anything happening yet because we haven’t bound any data to the control. we will see data binding option in a minute.
Providing a Placeholder:
ComboBox wrapper, similar to that of AutoComplete wrapper provides an option to put a placeholder text in the control when there is no value selected by the user. The placeholder will be displayed only when user has not made any choice; once he makes a choice the placeholder text will not be shown instead the text of the selected item will be shown. We set placeholder using the Placeholder() method which accepts the string to be displayed as placeholder. Here is the code snippet:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .Placeholder("Select a value...")
4: )
And here is the output of the above code:
Providing Data Source:
So far we have been able to get the combobo on to the page with the instantiation code. Now we will see how to provide data to the combobox. The data source can be provided in three ways and they are:
-
BindTo – using BindTo() method, any IEnumerable data can be bound
-
Items – using Items() method, define items
-
DataSource – using the DataSource() method, define action method and controller to fetch data
Using BindTo() for data binding:
BindTo() method allows you to provide data to the Combobox control right at the time of instantiating the control. BindTo() method accepts any data items which is of type IEnumerable. Lets say we have a string of text to show in the combobox, we can write the code as below:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .Placeholder("Select a value...")
4: .BindTo(new string[] {"Bulgaria",
5: "United States",
6: "India","Australia",
7: "United Kingdom"}
8: )
9: )
As you can see, we just create a string array and bind it to the control. Here is the output of the above code:
Normally a combobox is used to show a lookup list where in the text inside the control is usually for the end user readability, where as the value stored in the database is usually an integer. So if your data source is a complex object and you want to show text and maintain value in the backend, you would need to set 2 extra properties for this to work correctly. They are DataTextField & DataValueField. Here is the code snippet to achieve this:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .HtmlAttributes(new { style = "width:250px"})
4: .Placeholder("Select a value...")
5: .DataTextField("Text")
6: .DataValueField("Value")
7: .BindTo(new List<SelectListItem>() {
8: new SelectListItem() {
9: Text = "Bulgaria", Value = "1"
10: },
11: new SelectListItem() {
12: Text = "Unites States of America", Value = "2"
13: },
14: new SelectListItem() {
15: Text = "India", Value = "3"
16: },
17: new SelectListItem() {
18: Text = "Australia", Value = "4"
19: },
20: new SelectListItem() {
21: Text = "United Kingdom", Value = "5"
22: }
23: }
24: )
25: )
In the above code snippet we create a new list of SelectListItem, bind it to the control and let the control know which property should be used to show the text & which property should be used to store the value of the selected item. The output will have no change as compared to previous example.
Using Items() for data binding:
Items() method allows you to define the items of the combobox control at the time of instantiating the control. If you ever have a scenario where the data to be bound to the control is static but you still need the flexibility of displaying text/value pair, you can use the Items() method. Here is the code snippet to use the Items() method:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .HtmlAttributes(new { style = "width:250px" })
4: .Placeholder("Select a value...")
5: .DataTextField("Text")
6: .DataValueField("Value")
7: .Items(item =>
8: {
9: item.Add().Text("Bulgaria").Value("1");
10: item.Add().Text("United States Of America").Value("2");
11: item.Add().Text("India").Value("3");
12: item.Add().Text("Australia").Value("4");
13: item.Add().Text("United Kindom").Value("5");
14: }
15: )
16: )
The output again will be the same as previous output.
Using DataSource() for data binding:
If you want to get the data for combobox from a controllers action method, you will need to use DataSource() method. This allows you to set the controller name and the action name from which the data will be retrieved at runtime by issuing an AJAX request. First lets look at the controller action method:
1: public JsonResult GetCountries()
2: {
3: var countries = new List<SelectListItem>
4: {
5: new SelectListItem{Text ="Bulgaria",
6: Value="1"},
7: new SelectListItem{Text ="United States of America",
8: Value="2"},
9: new SelectListItem{Text ="India",
10: Value="3"},
11: new SelectListItem{Text ="Australia",
12: Value="4"},
13: new SelectListItem{Text ="United Kingdom",
14: Value="5"},
15: };
16: return Json(countries, JsonRequestBehavior.AllowGet);
17: }
The action method is a standard action method and the only difference is that it is returning a JsonResult. This is because the control will issue a AJAX request on loading on the client side to fetch the data. Now here is the code snippet to instantiate the control:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .HtmlAttributes(new { style = "width:250px" })
4: .Placeholder("Select a value...")
5: .DataTextField("Text")
6: .DataValueField("Value")
7: .DataSource(source =>
8: {
9: source.Read(read =>
10: {
11: read.Action("GetCountries", "Home");
12: });
13: })
14: )
Pay attention to the DataSource() method declaration. We are providing it a configurator which knows what is the read URL to fetch the data. We are just providing the controller
& action name. The control will automatically issue a AJAX request to get the data as a JSON payload.
Serverside Filtering:
If we don’t specify any filter strategy i.e. server or client, the combobox control will use the client side filtering by default. If we have huge list then it is wise to filter the data on the server instead of sending everything to client and then filter on the client side. For the server side filtering to work, we should first set the filter type and then enable the ServerSideFiltering flag on the data source itself. We can set the filter options with valid values equal to “StartsWith” or “Contains”. Here is the action method which depicts the server side filtering:
1: public JsonResult GetCountries(string text)
2: {
3: var countries = new List<SelectListItem>
4: {
5: new SelectListItem{Text ="Bulgaria",
6: Value="1"},
7: new SelectListItem{Text ="United States of America",
8: Value="2"},
9: new SelectListItem{Text ="India",
10: Value="3"},
11: new SelectListItem{Text ="Australia",
12: Value="4"},
13: new SelectListItem{Text ="United Kingdom",
14: Value="5"},
15: };
16: if (!string.IsNullOrEmpty(text))
17: {
18: countries = (from item in countries
19: where item.Text.StartsWith(text)
20: select item).ToList();
21: }
22: return Json(countries, JsonRequestBehavior.AllowGet);
23: }
Here is the combobox definition:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .HtmlAttributes(new { style = "width:250px" })
4: .Placeholder("Select a value...")
5: .DataTextField("Text")
6: .DataValueField("Value")
7: .Filter(FilterType.StartsWith)
8: .DataSource(source =>
9: {
10: source.Read(read =>
11: {
12: read.Action("GetCountries", "Home");
13: }).ServerFiltering(true);
14: })
15: .Template("<span><img src='/Content/Images/${data.Value}.jpg' " +
16: "width='20' height='20' /> ${data.Text}</span>")
17: )
Controlling the data binding:
The items of the combobox control will be queries as soon as the control is instantiated on the client side. If you do not wish to go with this behavior, the control provides a mechanism to control when to load the items. You can set the control to load the items either user types in the combobox or when he open the options list. This is possible due to a method called AutoBind(). This takes a boolean value to indicate whether to load data on instantiation or wait for the user interaction with the control. Here is the code snippet to set this behavior:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .HtmlAttributes(new { style = "width:250px" })
4: .Placeholder("Select a value...")
5: .DataTextField("Text")
6: .DataValueField("Value")
7: .Filter(FilterType.StartsWith)
8: .DataSource(source =>
9: {
10: source.Read(read =>
11: {
12: read.Action("GetCountries", "Home");
13: }).ServerFiltering(true);
14: })
15: .Template("<span><img src='/Content/Images/${data.Value}.jpg' " +
16: "width='20' height='20' /> ${data.Text}</span>")
17: .AutoBind(false)
18: )
Custom templates for combobox item display:
Consider a scenario where in you want to customize the combobox item display on the client side. i.e. let us say we want to show the country flag before the country name which is displayed as a text of the combobox item. Well, the control provides a way to provide our custom template which will be used for display on the client side. The Template() method accepts a HTML markup which will be used to display the item instead of the default template the control uses. You access data item using the {data.<property name>} syntax inside the custom template markup. Here is the code snippet to work with Template() method:
1: @(
2: Html.Kendo().ComboBox().Name("kcombobox")
3: .HtmlAttributes(new { style = "width:250px" })
4: .Placeholder("Select a value...")
5: .DataTextField("Text")
6: .DataValueField("Value")
7: .DataSource(source =>
8: {
9: source.Read(read =>
10: {
11: read.Action("GetCountries", "Home");
12: });
13: })
14: .Template("<span><img src='/Content/Images/${data.Value}.jpg' " +
15: "width='20' height='20' /> ${data.Text}</span>")
16: )
Notice the Template() method and the markup inside it. We use {data.Value} to access the value of the bound data item and {data.Text} to access the text of the bound data item. Using this method you can pretty much customize the UI if the comboxbox item.
Cascading Comboboxes:
One of the typical scenarios of web is to cascade a child combobox based on the item selected in a parent combobox. for e.g. consider a categories combobox and a products combobox. We want the categories combobox to filled with items first, user should select a category and then the products belonging to that category to be shown. With Kendo Combobox this is fairly simple as it allows a method called CascadeFrom(). As the name goes we just need to pass the parent combobox based on which we need to cascade. To illustrate this, consider that we have 2 action methods named GetCategories() and GetProducts(). For getting the products we need to know the category id. So here is the code snippet for this:
1: public JsonResult GetCascadeCategories()
2: {
3: var northwind = new NorthwindDataContext();
4:
5: return Json(northwind.Categories.Select(
6: c => new { CategoryId = c.CategoryID,
7: CategoryName = c.CategoryName }),
8: JsonRequestBehavior.AllowGet);
9: }
1: public JsonResult GetCascadeProducts(string categories)
2: {
3: var northwind = new NorthwindDataContext();
4: var products = northwind.Products.AsQueryable();
5:
6: if (!string.IsNullOrEmpty(categories))
7: {
8: products = products.Where(p => p.CategoryID.ToString() == categories);
9: }
10:
11: return Json(products.Select(p => new {
12: ProductID = p.ProductID,
13: ProductName = p.ProductName}),
14: JsonRequestBehavior.AllowGet);
15: }
Here is the combobox definition for categories:
1: @(Html.Kendo().ComboBox()
2: .Name("categories")
3: .Placeholder("Select category...")
4: .DataTextField("CategoryName")
5: .DataValueField("CategoryId")
6: .DataSource(source => {
7: source.Read(read => {
8: read.Action("GetCascadeCategories", "Home");
9: });
10: })
11: )
Here is the combobox definition for Products:
1: @(Html.Kendo().ComboBox()
2: .Name("products")
3: .Placeholder("Select product...")
4: .DataTextField("ProductName")
5: .DataValueField("ProductID")
6: .DataSource(source => {
7: source.Read(read =>
8: {
9: read.Action("GetCascadeProducts", "ComboBox")
10: .Data("filterProducts");
11: })
12: .ServerFiltering(true);
13: })
14: .Enable(false)
15: .AutoBind(false)
16: .CascadeFrom("categories")
17: )
18: <script>
19: function filterProducts() {
20: return {
21: categories: $("#categories").val()
22: };
23: }
24: </script>
Note the usage of CascadeFrom() method. We pass in the name of the categories combobox. The AutoBind() is set to false. So these two settings make sure that products combobox is not loaded when no categories is selected. When user selects a category, that’s when products combobox will issue the AJAX request for getting list of products. Since we need to know what category is selected, we make use of the additional data concept on the data source read and pass in the selected categories value. This is done using the filterProducts() javascript method.
Here is the output of the same:
Client side access to combobox:
Using the Jquery data() method we can access the Keno Combobox from the client side. You may have a scenario where in you want to load the combobox based on a button click. Here is the code to achieve that:
1: <script>
2: var kendoComboBox = null;
3: $(document).ready(function () {
4:
5: kendoComboBox = $("#kcombobox").data("kendoComboBox");
6:
7: $("#button").click(function () {
8: kcb.dataSource.read();
9: });
10: })
11: </script>
First we declare a global variable which will hold the reference of the combobox. Then on page load we make use of the data() method to get access to the control. On a button click, we just access the dataSource property and issue a read() method on it.
For a complete list of client side API, have a look at this help documentation.
Summary:
In this post, we looked at how easy it is to instantiate a combobox control and set it up for data binding. We also looked at some of the features such as auto bind i.e. control when the data is bound to the control, different ways of data binding the control, cascading based on a item selection of another combobox and last but not the least how to access the combobox from the client side. Hope this gives you a jumpstart at using the Kendo Combobox Wrapper for ASP.NET MVC .
Till next time – Happy Coding!
Pingback: Getting Started Series on Kendo UI Wrappers for ASP.NET MVC « Telerik Helper
Looks like you have a typeo, if I’m not mistaken, {kcb.dataSource.read();} should be {kendoComboBox.dataSource.read();}…
-Cheers.