Optgroup with the Kendo UI Combobox

Kendo UI is a great framework to use, sometimes what you are looking for is not out of the box, but it’s not really difficult to make it work as you want to.

Kendo provides a combobox and a dropdown control, the following article uses the combobox for the example but applies for both controls.

What I want to achieve is to build a combobox with an optgroup.

Here is the raw html sample

<select>
 <optgroup label="Group 1">
 <option value="Value0">Option N°0</option>
 <option value="Value1">Option N°1</option>
 <!-- ... -->
 </optgroup>
 <optgroup label="Group 2">
 <option value="Value0">Option N°0</option>
 <option value="Value1">Option N°1</option>
 <!-- ... -->
 </optgroup>
 <optgroup label="Group 3">
 <option value="Value0">Option N°0</option>
 <option value="Value1">Option N°1</option>
 <!-- ... -->
 </optgroup>
 </select>

Using kendo, you can define a combox using the MVC wrappers this way

@(Html.Kendo().ComboBox()
 .Name("democombo").HtmlAttributes(new { style = "width:300px;" })
 .Filter("contains")
 .Placeholder("Select an item ...")
 .Items(x =>
 {
 // add some values
 x.Add().Text("Group 1");
 for (int i = 0; i < 10; i++)
 {
 x.Add().Value("value" + i).Text("Option N°" + i);
 }
 x.Add().Text("Group 2");
 for (int i = 0; i < 10; i++)
 {
 x.Add().Value("value" + i).Text("Option N°" + i);
 }
 //....

}))

it will look like this :

kendo combobox

There is a nice style and a search functionality, but since there is no way to specify that we want an optgroup, you cannot spot the difference between a simple item and a “group” item

Fortunately, it’s not that hard to make it work like if this option was existing.

Kendo ships with a template engine that will help

if we change a bit our code to make a clever user of the template :


@(Html.Kendo().ComboBox()
 .Name("democombo").HtmlAttributes(new { style = "width:300px;" })
 .Filter("contains")
 .Placeholder("Select an item ...")
 .Items(x =>
 {
x.Add().Text("Group 1").Value("optgroup");// notice that we give a value
 // ...
}).TemplateId("scriptTemplate"))

the template

// we use the value
<script id="scriptTemplate" type="text/x-kendo-template">
 # if ( Value=="optgroup") { #
 <div class="optgroup">#=Text#</div>
 # } else { #
 <div class="option">#=Text#</div> # } #
</script>

and the css


.k-list .k-item .optgroup {
 background: #fff;
 color: #000;
 font-weight: bold;
 }
 .k-list .k-item .option {
 padding-left: 15px;
 }

we are getting this result

kendo ui template

It’s nice but there is still two problems: the style on hover change, and the item is clickable

we can make use of the kendo combobox events to resolve that :


@(Html.Kendo().ComboBox()
 .Name("democombo").HtmlAttributes(new { style = "width:300px;" })
 .Filter("contains")
 .Placeholder("Select an item ...")
 .Items(x =>
 {
x.Add().Text("Group 1").Value("optgroup");
// ...
}).TemplateId("scriptTemplate").Events(events =>
 {
 events.DataBound(@<text>function(e){
// disable the click, and add a special class on the parent (which is the real item)
       $(".optgroup").parent().click(false).addClass("optgrouplistitem");
 }</text>);>
 }))

Some CSS to override the normal kendo “hover” style


.k-popup .k-list .k-item.optgrouplistitem.k-state-hover{
 border: none;
 color: #000;
 border-radius: 0;
 background: none;
 padding: 1px 5px 1px 5px;
 box-shadow: none;
 }

and we end with this

kendo optgroup

Complete code

<style type="text/css">
 .k-list .k-item .optgroup {
 background: #fff;
 color: #000;
 font-weight: bold;
 }

 .k-popup .k-list .k-item.optgrouplistitem.k-state-hover {
 border: none;
 color: #000;
 border-radius: 0;
 background: none;
 padding: 1px 5px 1px 5px;
 box-shadow: none;
 }

.k-list .k-item .option {
 padding-left: 15px;
 }
</style>

 

<script id="scriptTemplate" type="text/x-kendo-template">
 # if ( Value=="optgroup") { #
 <div class="optgroup">#=Text#</div>
 # } else { #
 <div class="option">#=Text#</div> # } #
</script>

 

@(Html.Kendo().ComboBox()
 .Name("democombo").HtmlAttributes(new { style = "width:300px;" })
 .Filter("contains")
 .Placeholder("Select an item ...")
 .Items(x =>
 {
 x.Add().Text("Group 1").Value("optgroup");
 for (int i = 0; i < 10; i++)
 {
 x.Add().Value("value" + i).Text("Option N°" + i);
 }
 x.Add().Text("Group 2").Value("optgroup");
 for (int i = 0; i < 10; i++)
 {
 x.Add().Value("value" + i).Text("Option N°" + i);
 }
 x.Add().Text("Group 3").Value("optgroup");
 for (int i = 0; i < 10; i++)
 {
 x.Add().Value("value" + i).Text("Option N°" + i);
 }

}).TemplateId("scriptTemplate").Events(events =>
 {

events.DataBound(@<text>function(e){
 $(".optgroup").parent().click(false).addClass("optgrouplistitem");
 }</text>);
 }))

Incoming search terms:

  • kendo combobox
  • kendoComboBox template tree
  • kendoDropDownList and optgroup
  • kendo select group items
  • kendocombobox
  • optgroup filter
  • kendo ui model for combobox
  • Kendo() DropDownList TemplateId
  • kendo optgroup
  • filter the kendo drop down list with 2 or 3 drop donlist

Quick tip : Master-Child checkboxes with jQuery

Here is a code that is really often asked.

I was asked how to code a master-child checkboxes using jQuery.

The requirements were :

  1. We want a “master” checkbox that the “child” checkboxes will mimic.
  2. We want this checkbox to be cheched if all child checkboxes are checked.
  3. We want this checkbox to be unchecked if all child checkboxes are not checked anymore.

Here is what I came with (check the demo here):

HTML markup :


<label>
 <input type="checkbox" id="checkall" />
 ALL</label>
 <hr />
 <div id="checkboxes">

<label>
 <input type="checkbox" />
 test 1</label><br />
 <label>
 <input type="checkbox" />
 test 2</label><br />
 <label>
 <input type="checkbox" />
 test 3</label><br />
 <label>
 </div>

jQuery part for requirement 1 :


$("#checkall").on("change", function () {
 $('#checkboxes input[type="checkbox"]').prop("checked", $(this).is(":checked"));
 });

Set all the checkboxes inside elements with class “checkboxes” to the value of the input with id “checkall”

jQuery part for requirements 2 and 3 :


$('#checkboxes [type="checkbox"]').on("change", function () {
 $("#checkall").prop("checked", $('#checkboxes input[type="checkbox"]:checked').length === $('#checkboxes input[type="checkbox"]').length);
 });

Set the element with id “checkall” to the answer to the question “is the number of checkboxes equal to the number of checked checkboxes”

You can check the demo here

I want a simpler way to assign icons to my jquery ui buttons

JQuery UI has a nice widget for the buttons, problem is, imoh, that when I want to assign an icon for a button I have to do it for each button separatly.

Here is the sample from the jquery ui website :

<!doctype html>

<html lang="en">
<head>
 <meta charset="utf-8" />
 <title>jQuery UI Button - Icons</title>
 <link rel="stylesheet" href="http://code.jquery.com/ui/1.10.1/themes/base/jquery-ui.css" />
 <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
 <script src="http://code.jquery.com/ui/1.10.1/jquery-ui.js"></script>
 <link rel="stylesheet" href="/resources/demos/style.css" />
 <script>
 $(function() {
 $( "button:first" ).button({
 icons: {
 primary: "ui-icon-locked"
 },
 text: false
 }).next().button({
 icons: {
 primary: "ui-icon-locked"
 }
 }).next().button({
 icons: {
 primary: "ui-icon-gear",
 secondary: "ui-icon-triangle-1-s"
 }
 }).next().button({
 icons: {
 primary: "ui-icon-gear",
 secondary: "ui-icon-triangle-1-s"
 },
 text: false
 });
 });
 </script>
</head>
<body>

<button>Button with icon only</button>
<button>Button with icon on the left</button>
<button>Button with two icons</button>
<button>Button with two icons and no text</button>

</body>
</html>

jquerysample

It works but I think it’s not the easiest way, I would prefer to configure the html tag with a property to say what is the icon I want.

So my solution is to use the data attribute of the element on which we want the button widget to be applied


<a href="#" class="button" data-icon="ui-icon-pencil" id="myid">my text button</a>

and in the document ready of the page

 $(document).ready(function () {

 $(".button").button({
 create: function (event, ui) {
 var icon = $(this).data("icon");
 if (HasValue(icon)) {
 $(this).button("option", "icons", { primary: icon });
 }
 }
 });
});

Basicly, when a button is created, I check if I have a data-icon property setted, and if so I use it to set the primary icon property of the button.

textbutton

I’m working with ASP.NET, so if I use WebForms I put that little piece of code in my master page, and if I’m workgin with MVC, I put the code in the _layout.cshtml file.
This way I don’t have to worry about setting the icon for each button.

But where are the icons defined ?

The example I used sooner (ui-icon-pencil) is a class of the icon set of a jquery mobile theme (you can see what’s available on the themeroller page).

If I want to define a custom icon, I do it this way

in the CSS:

.ui-icon.ui-icon-xlsx
{
 background: transparent url('images/xlsx.png') no-repeat;
}

and in the html:

<a href="#" class="button" data-icon="ui-icon-pdf">XLSX</a>

xlsxbbbb

Incoming search terms:

  • ASP NET jquery ui button
  • assign ui
  • button(option icons
  • button(option icons not working
  • jquery icons
  • jquery mobile icon from custom css
  • jquery ui button text after custom icon

A simple local storage explorer

When building web apps using the html5 local storage, it’s sometimes hard to check what is actually stored in the browser’s local storage

Of course the chrome resources explorer is nice, but there is no formatting when we want to see datas stored as json

And the technique used to see what’s in the local storage is not the same in all browsers

So I ended up with creating a small html page using some javascript projects such as jQuery, highlight and vkbeautify

It’s not really beautiful, but I think it might be helpful

You can download it here if you want to use it :Â http://www.sambeauvois.be/codes/20120611.sbe.LocalStorageExplorer.zip

Incoming search terms:

  • active localstorage in ie
  • chrome storage explorer
  • localstorage in ie and chrome
  • storage itvds local
  • vkbeautify

Simple proxy to bypass cors

CORS is a pain in the ass, all works great with chrome and firefox,but, as often, internet explorer doesn’t (it should work with ie 10 but you know…)

So the proxy solution is simple and works, even if I would prefer a full html/jquery solution.

To create a proxy for the get requests it’s simple.

Create an asp.net webform, add this in the pageload.


protected void Page_Load(object sender, EventArgs e)
{
 string serviceUrl = HttpContext.Current.Request.Params["service"];
 if (string.IsNullOrEmpty(serviceUrl))
 {
  return;
 }

 string query = string.Empty;
 int firstParamIndex = HttpContext.Current.Request.Url.Query.IndexOf('&');

 if (firstParamIndex > -1)
 {
  query = HttpContext.Current.Request.Url.Query.Remove(0,firstParamIndex+1);
 }

 string service = serviceUrl + "?" + query;

 WebClient client = new WebClient();

 foreach (string headerKey in HttpContext.Current.Request.Headers.Keys)
 {
  try
  {
    client.Headers[headerKey] = HttpContext.Current.Request.Headers[headerKey];
  }
  catch (Exception ex)
  {
    System.Diagnostics.Debug.WriteLine(ex.Message);
  }
 }

 // specify encoding : avoid special characters to be unrecognized.
 client.Encoding = Encoding.UTF8;
 string resultString = client.DownloadString(service);

 // carriage returns.
 Response.Write(resultString.Replace(@"\u000d\u000d", "<br/>"));
}

you can restrict some headers this way


protected void Page_Load(object sender, EventArgs e)
{
 string[] allowedHeaders =
 {
  "x-headers1",
  "x-headers2",
  "x-headers3"
 };

 string serviceUrl = HttpContext.Current.Request.Params["service"];
 if (string.IsNullOrEmpty(serviceUrl))
 {
  return;
 }

 string query = string.Empty;
 int firstParamIndex = HttpContext.Current.Request.Url.Query.IndexOf('&');

 if (firstParamIndex > -1)
 {
 query = HttpContext.Current.Request.Url.Query.Remove(0,firstParamIndex+1);
 }

 string service = serviceUrl + "?" + query;

 WebClient client = new WebClient();

 foreach (string headerKey in HttpContext.Current.Request.Headers.Keys)
 {
  if (allowedHeaders.Contains(headerKey))
  {
   try
   {
     client.Headers[headerKey] = HttpContext.Current.Request.Headers[headerKey];
   }
   catch (Exception ex)
   {
     System.Diagnostics.Debug.WriteLine(ex.Message);
   }
  }
 }

 // specify encoding : avoid special characters to be unrecognized.
 client.Encoding = Encoding.UTF8;
 string resultString = client.DownloadString(service);

 // carriage returns.
 Response.Write(resultString.Replace(@"\u000d\u000d", "<br/>"));
}

In your web client :


if (jQuery.support.ajax)
{
 $.ajax({
 headers:
 {
  "x-headers1": "header value 1",
  "x-headers2": "header value 2",
  "x-headers3": "header value 3"
 },
 contentType: "application/json; charset=utf-8",
 dataType: "json",
 url: "youpage.aspx?service=yourservicecompleteurl",
 data:
 {
  param1: value1,
  param2: value2
 },
 success: function (msg)
 {
  callback(msg);
 },
 error: function (errormsg)
 {
  if (errorCallback != 'undefined')
  {
  errorCallback(errormsg);
  }
 }
 });
 }
 else
 {
  alert('You browser doesnt support ajax.');
 }

I could use a webservice, but it would force me to do POST requests and I doesn’t want to make changes in my jscripts.

[Update 20120405 ]

Here is the full proxy code, which handles both get and post requests :


using System;
using System.Linq;
using System.Web;
using System.Text;
using System.Net;
using System.IO;

namespace yournamespace
{
 public partial class Proxy : System.Web.UI.Page
{
/// <summary>
/// Definition of the headers to transfer.
/// </summary>
private static string[] requiredHeaders =
{
"x-your-required-header-1",
"x-your-required-header-2",
"x-your-required-header-3",
"Content-type"
};

/// <summary>
/// Overrides the onload event to handle get and post requests.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{
bool isPost = string.Equals(HttpContext.Current.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase);
string serviceUrl = HttpContext.Current.Request.Params["service"];
if (string.IsNullOrEmpty(serviceUrl))
{
return;
}

string service = serviceUrl + (isPost ? "" : "?" + GetQuery());
WebClient client = new WebClient();

// copy required headers
foreach (string headerKey in HttpContext.Current.Request.Headers.Keys)
{
if (requiredHeaders.Contains(headerKey))
{
try
{
client.Headers[headerKey] = HttpContext.Current.Request.Headers[headerKey];
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}

// specify encoding : avoid special characters to be unrecognized.
client.Encoding = Encoding.UTF8;
string resultString = string.Empty;
try
{
if (isPost)
{
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");

using (MemoryStream str = new MemoryStream())
{
HttpContext.Current.Request.InputStream.CopyTo(str);
byte[] result = client.UploadData(service, str.ToArray());
resultString += Encoding.UTF8.GetString(result);
}
}
else // GET
{
resultString = client.DownloadString(service);
}
}
catch (WebException wex)
{
System.Diagnostics.Debug.Write(wex);
resultString = "<h1>An error occured : " + wex.Message + "</h1>";
resultString += "<br/>Status : " + wex.Status;
if (wex.Status == WebExceptionStatus.ProtocolError)
{
HttpWebResponse httpResponse = wex.Response as HttpWebResponse;
if (httpResponse != null)
{
resultString += string.Format("<br/>Status Code : {0}", httpResponse.StatusCode);
resultString += string.Format("<br/>Status Description : {0}", httpResponse.StatusDescription);
}
}
resultString += "<br/><br/>Requested service : " + service;
}
catch (Exception ex)
{
System.Diagnostics.Debug.Write(ex);
resultString = "<h1>An error occured : " + ex.Message + "</h1>";
resultString = ex.GetFullMessage();
resultString += "<br/><br/>requested service : " + service;
}
finally
{
client.Dispose();
}
Response.Clear();
Response.Write(resultString);
}

/// <summary>
/// Gets the query part.
/// </summary>
/// <returns></returns>
private static string GetQuery()
{
string query = string.Empty;
int firstParamIndex = HttpContext.Current.Request.Url.Query.IndexOf('&');
if (firstParamIndex > -1)
{
query = HttpContext.Current.Request.Url.Query.Remove(0, firstParamIndex + 1);
}

return query;
}
}
}

Incoming search terms:

  • cors proxy
  • bypass cors jquery
  • corsproxy
  • bypass cors
  • CORS and proxy
  • how to bypass cors
  • catch (webexception wex) sharepoint
  • bypass chrome cors
  • use proxy to support browser that doesnt support cors
  • ajax cors request behind client proxy