Telerik components for asp.net: learning to live with RADical family. (On using radScheduler in an MVC app)

Telerik is a Friend of codebetter and they deserve some more attention. In this post I will explore some of my recent experiences with their components for asp.net. There are two suites of them. On the MVC one I can be short. The components work very well and have a fluent api which fits very well in asp.net MVC. Both user and developer will be quite satisfied. On the Telerik site is a set of live demo’s which tells all far better than I can do here.

Just one code snippet to draw your attention.

@using Telerik.Web.Mvc.UI

@model int

<div id=”dbcDiv”>

@(Html.Telerik().TabStrip().Name(“DBCs”)

    .Items(tabs =>

               {

                   tabs.Add().Text(“Status”).LoadContentFrom(“DBCStatus”, “ZorgTraject”, new {idDBC = Model});

                   tabs.Add().Text(“Activiteiten”).LoadContentFrom(“Activiteiten”, “ZorgTraject”, new {idDBC = Model});

                   tabs.Add().Text(“Centen”).LoadContentFrom(“Afleiding”, “ZorgTraject”, new {idDBC = Model});

               }

           )

    .SelectedIndex(0)

)

</div>

 

This results in a tabstrip where the content is loaded on demand from controller actions. It speaks for itself for anyone working with MVC.

The Telerik AJAX library deserves some more attention. Nearly, but not all, of its controls have counterparts in the MVC library. The claim is that the AJAX controls do work on MVC pages, with some small restrictions. We needed the scheduler, a control for planning appointments. Appointments with many resources like workers, visitors, budgets and so on. The scheduler has only an AJAX version. In the remaining of this post I will demonstrate how we got it to work and enriched it’s possibilities using MVC components.

The controls in the Ajax library are named RAD controls. Some years ago RAD was a flaming topic on Codebetter. I don’t want to drag old cows from the ditch but do like to kick against some thighs occasionally. You can use either a Dutch sayings book or your own imagination to find out what that means. Yes, you will find quite some spaghetti drag and drop code when googling around on RADcontrols. No, here I only wanted to tickle your attention.

An MVC page for the RadScheduler

There are some restrictions on using the RAD-scheduler on an MVC page .

  • Use the aspx ViewEngine. The Razor view engine does not understand the Telerik (or any other custom) tags. The good thing is that you can use ascx partial views on a Razor page. The bad thing is that you cannot use Razor views on an aspx page. All Telerik demo’s are presented using both view engines.
  • The page should include a form which runs server side. This can be a problem which we will meet later in the custom form.
  • The scheduler should run “web-service” mode. That is it gets all it’s data from an (AJAX) web-service. This is good for the user-experience but knocks out the complete server side api of the scheduler. Most server side events do have a client side (JavaScript) counterpart. But not all of them. Running client side makes customizing resources hard as well. More on that later.

This will be the essentials of the webpage:

<%@ Page Language=”C#” Inherits=”System.Web.Mvc.ViewPage<dynamic>”%>

<%@ Import Namespace=”System.Net” %>

<%@ Import Namespace=”Telerik.Web.Mvc.UI” %>

 

<!DOCTYPE html>

 

<Html>

    <head runat=”server”>

        <script runat=”server”>

            private void SetAuthCookie(object sender, ResourcesPopulatingEventArgs e)

            {

                HttpCookie cookie = FormsAuthentication.GetAuthCookie(User.Identity.Name, false);

                string cookieHeader = string.Format({0}={1}, cookie.Name, cookie.Value);

                e.Headers.Add(HttpRequestHeader.Cookie, cookieHeader);

            }

        </script>

    </head>

 

    <body>

 

        <% =Html.Telerik().StyleSheetRegistrar().DefaultGroup(group => group.Add(“telerik.common.css”))%>

        <form runat=”server” ID=”Form1″>

            <telerik:RadScriptManager runat=”server” EnableScriptGlobalization=”true”>

            </telerik:RadScriptManager>

            <telerik:RadScheduler  ID=”Agenda” runat=”server”

                                   OnResourcesPopulating=”SetAuthCookie”>

                <WebServiceSettings Path=”~/Services/AgendaWebService.asmx” ResourcePopulationMode=”ServerSide” />

            </telerik:RadScheduler>

        </form>

        <%=Html.Telerik().ScriptRegistrar()%>

    </body>

</Html>

The telerik stylesheets are registered, followed by the form containing the scheduler and finished by the Telerik scriptmanager. The webservice is a simple internal asmx, more on that later. Setting the path to the webservice is not enough. On a site requiring authentication, FI by forms authentication, the service will require authentication as well. The authentication cookie is in the session, by default a web service is sessionless. The SetAuthCookie adds the required cookie to the web service request. Setting it is hooked into OnResourcesPopulating, the first event the scheduler will fire.

From webservice to the repository

The web service providing the appointment data is a multi-stage missile. This service should implement a number of methods. These methods return and accept AppointmentData objects. This is a class in the Telerik.Web.UI namespace with properties for the bare essentials of an appointment. In case you want to pass more then that you do so using the Attributes property, which is a complete dictionary.

The webservice methods look like this

[WebMethod]

public IEnumerable<AppointmentData> GetAppointments(SchedulerInfo schedulerInfo)

{

    return Controller.GetAppointments(schedulerInfo);

}

 

A full list of the expected methods is in the Telerik docs.

To interact with your data you need a controller object, the next stage.

private WebServiceAppointmentController Controller

{

    get { return _controller ?? (_controller = new WebServiceAppointmentController(Agenda)); }

}

 

 

The WebServiceAppointmentController lives also in the Telerik.Web.Ui namespace. It’s constructer requires a Provider, which is the third stage.

private AgendaProvider Agenda

{

    get { return _agenda ?? (_agenda = new AgendaProvider()); }

}

 

A provider inherits from SchedulerProviderBase, another class in Telerik.Web.UI. By overriding its members your data is passed to and from the scheduler appointments.

 

public class AgendaProvider : SchedulerProviderBase

{

 

 

    public override IEnumerable<Appointment> GetAppointments(ISchedulerInfo schedulerInfo)

    {

        var repository = DataManager.AfspraakRepository(true);

        var query = repository.Query().Where(a => a.EindTijd >= schedulerInfo.ViewStart).Where(a => a.BeginTijd <= schedulerInfo.ViewEnd);

        return repository.List(query).Select(Appointment).ToList();

    }

 

    private Appointment Appointment(Afspraak afspraak)

    {

        var result = new Appointment

        {

            ID = afspraak.Id,

            Start = afspraak.BeginTijd,

            End = afspraak.EindTijd,

            Subject = Agenda.OnderwerpAsHtml(afspraak),

            Description = afspraak.Notitie,

            RecurrenceRule = “”

        };

        return result;

    }

 

The schedulerInfo passed in contains the information on the selected period. The repository is queried, the private Appointment method creates a Telerik Appointment out of my afspraak (Dutch for appointment) object.

The gotcha here is the Appointment object, also from Telerik.Web.UI, which has loads and loads of interesting members. You can set the properties or try to read their values but passing through the webservice all data will be lost. Just stick to properties also found in the AppointmentData class.

A custom appointment details form

So far the RAD scheduler works nice and well layered. At first sight the three layers in the webservice may look overdone. I guess it is the price for offering other possibilities beside web-service binding ? Anyway, on to adding some of the MVC goodies.

The scheduler has two built in detail forms, a simple in-line and a popup to edit things like the resources of an appointment. Resources are things like available people, rooms and other materials. The scheduler offers quite a lot of possibilities for adding and customizing resources to an appointment. There is also a lot of documentation on customizing the appointment detail form. In the end it was not enough to fit our needs. Our appointments have dynamic resources, for instance the available rooms depend on the assigned worker. There are ways to work with dynamic resources, the downside is that that only works with server-side data binding. We do use the built in resources for some things but ended up using our own form and our own data structures to set the details of an appointment.

Here the MVC controls come into view. There is a lovely modal MVC Window. No problem to add it to the page

 <% Html.Telerik().Window().Name(“AfspraakWindow”)

    .Title(“Details afspraak”)

    .Height(700).Width(1000)

    .Draggable(true)

    .Modal(true)

    .Visible(false)

    .Render();%>

 

The scheduler has lots of client events to hook into, their names are self describing. Popping up the window and filling it with content is done in such a client side event

function OnClientAppointmentSelect(sender, eventArgs) {

    var apt = eventArgs.get_appointment();

    var window = $(‘#AfspraakWindow’).data(‘tWindow’);

    window.ajaxRequest(‘/Agenda/Afspraak/?idAfspraak=’ + apt.get_id());

    window.center().open();

}

 

Again the beauty of the MVC api shows. By issuing an ajax request a controller can provide any view we need.

[NoCache]

public ActionResult Afspraak(int idAfspraak)

{

    return PartialView(new Agenda(Repository.Get(idAfspraak)));

}

 

Data is pulled out of the repository and a partial view is generated. Plain MVC. This view is a complete form with nice Telerik MVC datetime pickers, the Telerik MVC treeview, some serverside script, some javascript, all the usual.

AfspraakDetails

Here it is in action, in the background the scheduler.

Part of the markup, just to demonstrate the availability of the usual MVC stuff

<%if (Model.IsNieuweAfspraak && DataManager.Medewerker.HeeftRol(AdministratieveRol.MaaktPatientAfspraken))

{%>

<tr id=”PatientRow”>

    <td>

        <% =Html.LabelFor(a => a.Patient)%>   

    </td>

    <td>

        <% =Html.DropDownListFor(a => a.Patient,

                                DomainObjectModelBinder<Patient>.SelectListItems(Model.Patienten,

                                                                                    “DisplayNaam”),

                                “– Kies een patient –”,

                                new {onChange = “PatientGekozen();”, style = “width:100%”})%>

    </td>

</tr>

 

The window contains a complete “form”, with a lot of form-data I want to post to my controller. There is a gotcha here. Remember the scheduler living in a form. The window is still part of this same page. Issuing a full post will result in a post to that form. Trying an Ajax form based post also messed up the scheduler. Some script assembly was required to satisfy everybody.

This snippet of (abbreviated) script assembling post data

var laatste = “Laatste= “ + $(‘#Laatste’).val();

var aanvaard = “AanvaardConflicten=” + $(‘#AanvaardConflicten’).attr(‘checked’);

var data = laatste + ‘&’ + aanvaard;

$.post(‘/Agenda/Afspraak/?idAfspraak=<%=Model.Id%>, data, function(result) {

    if (result.Ok) {

        Agenda.rebind();

        CloseWindow();

    }});

 

Here the value of only two controls is used, just expand the string for any others. The assembled data is posted to my controller by issuing a Jquery post.. To the controller the data looks like any other usual form data.

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Afspraak(int idAfspraak, FormCollection form)

{

 

    var model = new AfspraakModel(idAfspraak, form["Laatste"]);

 

    var persist = model.Persist();

    return Json(new { Ok = persist });

}

 

The posted data is read from the form collection. Here (again abbreviated) I extract it by hand, it could also be used with (Try)UpdateModel. The controller returns some Json to notify the window of validation and persistence results. Making the circle round.

Winding down

The voyage through Telerik country has been an interesting one. Despite the somewhat frightening, almost old-fashioned, radical name the scheduler works well with all today’s tools. Most of the information on how to do that can be found on the Telerik web site. Also mentioned should be Telerik support. When it comes to to simple questions the response can be almost instantaneous. When it comes to deeper problems the response can take longer but does provide an answer. Which can be in the form of a complete web-cast to guide you through something. Hats off.

Telerik does also spend a lot of effort in marketing. Having spent a lot of time on their site I can no longer watch  the Carter Family (Kyle is not the only hillbilly on CB Smile) on YouTube without a Telerik ad popping up. That’s too much, even from a good friend.

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