Telerik, moving to Kendo

I’ve been pretty quiet lately. Spent all my time on our big app, working with the usual MVC, DDD, nHibernate and the like. Much to our content, so far we have managed to keep up with the ever changing landscape of Dutch mental healthcare. For our webpages we were using the Telerik MVC suite, in a previous post I already shared some of our experiences. Telerik is replacing the MVC suite with the new Kendo suite. Which has several very appealing options. Besides that support on the MVC suite is coming to an end. Time to move on.

Replacing all components in one go was not possible. Kendo has the same architecture as the MVC suite and a very similar syntax. But our app is just to large to change all in one go. According to the documentation it’s possible to mix the two suites, even in the same view. To get that actually to work took an effort beyond the faq. In this post I’ll dive into the details.

CSS

Both MVC and Kendo require some style sheets. In the mvc suite you need a StyleSheetRegistrar component to render the css links. Kendo follows the standard way.

Registering the style sheets

Code Snippet
  1. @Html.Telerik().StyleSheetRegistrar().DefaultGroup(group => group.Add(“telerik.common.css”).Add(“telerik.eposoffice2010silver.min.css”).Combined(true).Compress(true))
  2. <linkhref=”@Url.Content(“~/Content/kendo.common.min.css”)rel=”stylesheet”/>
  3. <linkhref=”@Url.Content(“~/Content/kendo.default.min.css”)rel=”stylesheet”/>
  4. <linkhref=”@Url.Content(“~/Content/epos/epos.css”)rel=”stylesheet”type=”text/css”/>

Completely straightforward

jQuery

When it comes to jQuery things get somewhat complicated. The MVC suite requires version <= 1.7, Kendo requires versions >= 1.9. These two are not compatible. Thank goodness the jquery-migrate script library patches the leaks, making it possible for the mvc suite to run using jquey 1.9. The gotcha is that the mvc suite uses a ScriptRegistrar component to register the Telerik scipts. By default this component will also register (the wrong version of) jQuery again. This is prevented by the jQuery(false) method of the registrar.

Code Snippet
  1. <scriptsrc=”@Url.Content(“~/Scripts/jquery-1.11.0.min.js”)type=”text/javascript”></script>
  2. <scriptsrc=”@Url.Content(“~/Scripts/jquery-migrate-1.2.1.min.js”)“></script>
  3. <scriptsrc=”@Url.Content(“~/Scripts/kendo.all.min.js” + “?v=” + version)“></script>
  4. <scriptsrc=”@Url.Content(“~/Scripts/kendo.aspnetmvc.min.js” + “?v=” + version)“></script>
  5. <scriptsrc=”@Url.Content(“~/Scripts/kendo.culture.nl-NL.min.js” + “?v=” + version)“></script>

The MVC suite scripts should be rendered at  the end of the page

Code Snippet
  1. @(Html.Telerik().ScriptRegistrar().jQuery(false).Globalization(true).DefaultGroup(group => group.Combined(true).Compress(true)))

To sum things up. The full master layout

Code Snippet
  1. @using Telerik.Web.Mvc.UI
  2. <!DOCTYPEhtml>
  3. <html>
  4. <head>
  5.     <metacharset=”utf-8″/>
  6.     <title>@ViewBag.Title</title>
  7.     @Html.Telerik().StyleSheetRegistrar().DefaultGroup(group => group.Add(“telerik.common.css”).Add(“telerik.eposoffice2010silver.min.css”).Combined(true).Compress(true))
  8.     <linkhref=”@Url.Content(“~/Content/kendo.common.min.css”)rel=”stylesheet”/>
  9.     <linkhref=”@Url.Content(“~/Content/kendo.default.min.css”)rel=”stylesheet”/>
  10.     <linkhref=”@Url.Content(“~/Content/epos/epos.css”)rel=”stylesheet”type=”text/css”/>
  11.     <scriptsrc=”@Url.Content(“~/Scripts/jquery-1.11.0.min.js”)type=”text/javascript”></script>
  12.     <scriptsrc=”@Url.Content(“~/Scripts/jquery-migrate-1.2.1.min.js”)“></script>
  13.     <scriptsrc=”@Url.Content(“~/Scripts/kendo.all.min.js”)“></script>
  14.     <scriptsrc=”@Url.Content(“~/Scripts/kendo.aspnetmvc.min.js”)“></script>
  15.     <scriptsrc=”@Url.Content(“~/Scripts/kendo.culture.nl-NL.min.js”)“></script>
  16.     @* Scripts required for ajax forms *@
  17.     <scriptsrc=”@Url.Content(“~/Scripts/jquery.unobtrusive-ajax.js”)type=”text/javascript”></script>
  18.     <scriptsrc=”@Url.Content(“~/Scripts/jquery.validate.min.js”)type=”text/javascript”></script>
  19.       <scriptsrc=”@Url.Content(“~/Scripts/jquery.validate.unobtrusive.min.js”)type=”text/javascript”></script>
  20.     @* App specific scripts *@
  21.     <scriptsrc=”@Url.Content(“~/Scripts/Epos.js”)type=”text/javascript”></script>
  22.       <scriptsrc=”@Url.Content(“~/Scripts/tiny_mce/tiny_mce.js”)type=”text/javascript”></script>
  23. </head>
  24. <body>
  25.     <scripttype=”text/javascript”>
  26.         kendo.culture(“nl-NL”);
  27.     </script>
  28.     <div>
  29.         <divid=”maincontent”>
  30.             @RenderBody()
  31.         </div>
  32.         @(Html.Telerik().ScriptRegistrar().jQuery(false).Globalization(true).DefaultGroup(group => group.Combined(true).Compress(true)))
  33.     </div>
  34. </body>
  35. </html>

In case your views use Ajax forms, rendered using Ajax.BeginForm, the ajax scripts are required. Imho these forms are a pita. The handling of events is quite entangling and, even worse, fields edited with a Kendo editor are not included the postdata. For most of our forms we do a straight post using extension methods. Alas, not all views have been adapted yet, so for now the scripts are still required. The good thing is that they still work in the new jquery scenario and don’t seem to bite anything else.

In action

Using this layout both suites can be combined on one page. Here’s a Kendo Colorpicker used within an mvc tabstrip

Untitled

Localization

The way the localization of the components work differs. Kendo is very much script based. For instance the titles of the buttons of the colorpicker above can only be set from script.

To standardize the look and feel of our components we build them using html extension methods, as described here. Also the Telerik Components, which have a lot of options which can be set.  The Kendo suite has an Html extension library, the extension methods in there provide options to configure the component. Alas this list of options is not complete, it is smaller in than the list of configuration options from script. FI it is not possible to set the captions from the extension method for the colorpicker.

All html extension methods do is render some script. It is no great deal to bypass the Kendo extension methods and render the script yourself. The Kendo components all follow the same pattern

Code Snippet
  1. <inputid=”colorpicker”type=”color”/>
  2. <script>
  3.     $(“#colorpicker”).kendoColorPicker({
  4.         buttons: false
  5.     })
  6. </script>

The main difference is that one component renders an input and the other a div.

To get all possibilities of configuration via script you can create your own extension methods which directly render the script

Code Snippet
  1. internalstaticMvcHtmlString KendoColorPickerFor<TModel>(thisHtmlHelper<TModel> htmlHelper, Expression<Func<TModel, string>> expression)
  2. {
  3.     /*
  4.         <input id=”colorpicker” type=”color” />
  5.         <script>
  6.         $(“#colorpicker”).kendoColorPicker({
  7.             messages: {
  8.             apply: “Update”,
  9.             cancel: “Discard”
  10.             }
  11.         })
  12.         </script>
  13.         */
  14.     var id = expression.NameBuilder(htmlHelper.ViewData.Model);
  15.     var value = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model;
  16.     var sb = newStringBuilder();
  17.     sb.AppendFormat(“<input id=’{0}‘ type=’color’ value=’{1}‘/>”, id, value);
  18.     sb.AppendLine(“<script>”);
  19.     sb.AppendFormat(“$(‘#{0}‘).kendoColorPicker({{ messages: {{ apply: ‘OK’, cancel: ‘Annuleren’ }} }})”, id);
  20.     sb.AppendLine(“</script>”);
  21.     returnMvcHtmlString.Create(sb.ToString());
  22. }

The captions are set to OK and annuleren. For now hard coded.

The NameBuilder method is the one from one of my previous stories. It is used to generate an unique id.

Small gotchas

So far mixing Kendo and the classical suite works well. We had two small gotchas so far.

  • Window stacking. In the mvc suite you can stack windows on top of each other. A popup in a popup, In the Kendo suite you can do that as well. This stacking is done using high z-index-es. The classical suite uses a higher range than Kendo. Resulting in a Kendo popup window launched from a classic window appearing behind it’s originator. You cannot stack Kendo and classical windows. Thanks goodness changing from classical window to Kendo window is no big deal.
  • Ajax forms. As mentioned inputs using Kendo components will exclude the edited fields from the ajax postdata. In our app we are switching to posting the data straight from script, using our postdata extension. Far more flexible and no more need for a form.

Winding down

Finding out the way the classical suite and Kendo require jQuery was somewhat of a hurdle. But now all works well and we can convert all further code at our pace. And please our users with a better look and feel. The way the Kendo window automatically adjusts to the size of it’s content is worth the migration on itself.

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.