Telerik blogs

Did you know that you can build web sites that AREN'T Single Page Applications? It's true! I just double checked, and it turns out that you can in fact build websites the good old fashioned way, and wouldn't you know it, it still works.

All heavy sarcasm aside, I fear that the sheer volume of the hype around HTML5 has now tainted our perception of what constitutes a modern web application. The truth of the matter is that the good old fashioned postback is at the core of the web platform, so guess what?! It's part of HTML5! Remember when we said things like "Friends Don't Let Friends Postback"? We were raising awareness of AJAX at the time - and that was good - but we somehow forgot, in the middle of all the excitement, the fundamentals of how to build responsible web applications.

Look, AJAX is just another incredibly powerful tool in your web development arsenal. Use it where it makes sense, but don't feel like you have to use it everywhere all the time. You become like the video game player that only learns one move in Streetfighter 2 and then you just keep mashing the same buttons. Nobody likes the person who always picks Blanka.

Of Modern And Mobile

As it turns out, mobile devices (while woefully underpowered in comparison to desktops) are really good at the old school HTTP Request game. In fact, there is a school of thought which purports that having the server returning a static page is the FASTEST way to reach the most devices with the least amount of work while maintaining the best overall performance across browsers.

Kendo UI Mobile was initially created for people who wanted to build Mobile Apps. These are apps that look and feel native. They could run on your server and be served up like a web site, or packaged as a native application with something like Icenium. In order to make that work, Kendo UI Mobile has a SPA framework baked right in. When you build a Kendo UI Mobile App, you are building a SPA. We spent countless hours investigating the nasty quirks of mobile browsers so that Kendo UI Mobile looks and behaves like a native application. Because lets face it: The browser is not just a way to view static documents anymore, it's our favorite application runtime.

But what if you don't want to build a SPA? What about just building a mobile web site? We realized this was important, and as of the Q1 2013 release, you can use Kendo UI Mobile to build mobile web sites.

In this article, we are going to build a mobile web application on top of SQL Server using MVC 4 and we are going to let the server do most of the work.

You can grab the code from GitHub, and run the demo.

File / New Project

Go ahead and rock those hot "File / New Project" skills you have perfected over the years, and create a new MVC 4 application. I created mine as an "Empty" application so I could start from scratch. What can I say? I like a clean slate.

I'm going to be using Northwind data here. Now the only person who is more tired than you of seeing the Northwind database, is me. That I promise. It just happens to be the only small SQL Server database I have lying around. Just remember: it's not about the data. Northwind in all it's glory is just a placeholder for whatever real world data you will be working with.

Setting Up A Layout With Kendo UI Mobile

In the Views folder, create a new folder called Shared and create a new MVC 4 Layout Page. Remove everything in the head of the page.

Remove Contents Of Head

<head>
  <!-- DELETE this tag -->
  <meta name="viewport" content="width=device-width" />
  <!-- make sure this tag is empty -->
  <title>@ViewBag.Title</title>
</head>

The first one of those is a viewport tag. The meta viewport tag is primarily responsible for telling the mobile device how to render the page. Should it zoom in on the content, or zoom way out an show the entire page with tiny text that you have to double tap on? Kendo UI Mobile will insert the right viewport information into the header, so you don't need to worry about it.

The second is the title of the page. This is also something Kendo UI Mobile will handle for us. We don't want to delete this tag entirely though, because then the page won't validate in Visual Studio, and that's slightly annoying. Just remove the @ViewBag.Title so you are left with just <title></title>.

Adding Kendo UI Mobile

If you don't have a copy of Kendo UI Mobile yet, you can download a 30 day trial version of Kendo UI Complete that contains everything you need. In your Kendo UI Mobile download, you are going to want to grab a few items.

Since we are going to be building a Kendo UI Mobile site today, I don't want to use Kendo UI Mobile's auto-adaptive OS rendering. Instead, we will be using the Kendo UI Mobile flat skin.

I usually create a folder under my Content folder which I call kendo and I place the following directories and style files there.

  • styles/images
  • styles/textures
  • styles/kendo.mobile.flat.min.css (not to be confused with kendo.flat.min.css)

Then I add the necessary JavaScript files to the Scripts directory.

  • kendo.mobile.min.js
  • jquery.min.js

You can also use jQuery from NuGet if you like. We recommend version 1.9.1 for use with Kendo UI Mobile.

Now we need to add Kendo UI Mobile to the _Layout page. I use the System.Web.Optimization packages so that I can just do @Styles.Render/@Script.Render. Since I started from an "Empty" template, I have to install the Microsoft.AspNet.Web.Optimization package from Nuget.

Install System.Web.Optimizations Reference

Install-Package Microsoft.AspNet.Web.Optimization

Then, I have to add a reference to this assembly in the Web.config file that's in the Views folder under the System.Web > Pages > Namespaces section. If you started with an MVC template of any sort, this is usually already done for you.

Add System.Web.Optimization To Web.config

<add namespace="System.Web.Optimization"/>

Now add the Kendo UI Flat skin css reference to the page.

Add Kendo UI Flat Skin CSS

@Styles.Render("~/Content/kendo/kendo.mobile.flat.min.css")

Lastly, add in the JavaScript files just before the closing <body> tag.

IMPORTANT: jQuery MUST be referenced BEFORE Kendo UI.

Add Kendo UI JavaScript And jQuery

@Scripts.Render("~/Scripts/jquery.min.js")
@Scripts.Render("~/Scripts/kendo/kendo.mobile.min.js")

Lastly, the @RenderBody() call is wrapped in a div by default. Just remove that parent div so that @RenderBody() is a direct child of the <body>.

Now we are ready to start building the web application.

Setting Up The Layout

When we setup a Kendo UI Mobile Application, we typically use something called a layout and then build everything in that context. Not be confused with an MVC layout, the Kendo UI Mobile layout is a chunk of HTML that will create any "sticky" navigation components that we want (i.e. NavBars, Tabstrips, ect). These layout components will appear on every view that we create. A Kendo UI Mobile View is just like an MVC View. Especially today since we will in fact be in fact using MVC views to create Kendo UI Mobile Views.

Before we create the layout, lets examine at what our application is going to look like...

We have two tabs. A Home tab and a Settings tab. The Home tab is really where all the functionality is. The Settings tab item is only there to help give some depth to this application and help setup a scenario we will have to work through.

The Application displays a list of Categories from the database and the Category Description. Clicking on one of these items loads a new view which has all of the products in that category. Clicking on a product loads in that product's detail in a form that we can edit and submit back to the database.

To create the Layout, use a div and give it a data-role of layout. These data- attributes are what give Kendo UI Mobile the information that it needs to transform the HTML into our mobile user interface. We give the layout a data-id attribute that we can reference from the individual Kendo UI Mobile views, thus declaring this layout as the layout for that particular view.

Notice that the @RenderBody call stays outside the layout. That might seem counter-intuitive, but the Kendo UI Mobile Layout actually expects all of it's 'views' to be top level elements, not children.

Adding A Kendo UI Layout

@RenderBody()

<div data-role="layout" data-id="main"></div>

We can add a Kendo UI Mobile NavBar component which will be the fixed header at the top of the screen. Navbars serve the purpose of telling us where we are in a navigation hierarchy, as well as housing some important buttons, like "back", or a button to add a new item. To make this Navbar stick to the top - and always the top - we put it inside a div with a role of header. We can dynamically set the title displayed in the Navbar by using a span with a role of view-title. This will pull the value from the data-title attribute on whichever view is currently loaded and use it as the title.

Add a Navbar To The Layout

@RenderBody()

<div data-role="layout" data-id="main">
  <div data-role="header">
    <div data-role="navbar">
      <span data-role="view-title"></span>
    </div>
  </div>
</div>

To create the Tabstrip, we will be using a Kendo UI Mobile Tabstrip widget and using a footer layout container to pin it to the bottom of the viewport.

Layout With Tabstrip

@RenderBody()

<div data-role="layout" data-id="main">
  <div data-role="header">
    <div data-role="navbar">
      <span data-role="view-title"></span>
    </div>
  </div>
  <div data-role="footer">
    <div data-role="tabstrip">
        <a href="/home" data-icon="home">Home</a>
        <a href="/settings" data-icon="settings">Settings</a>
    </div>
  </div>    
</div>

Notice that we have two tabs with icons - Home and Settings. It's time to build those views. In fact, we have to build at least one of them before we can even initialize this as a Kendo UI Mobile application.

Getting The Data Access Setup

Kendo UI Mobile requires at least one view to run. So far, we haven't defined any views. We're are going to use MVC Views as Kendo UI Mobile Views and let @RenderBody() do it's thing.

Since we need some data, I've added the Northwind database to my project and created an EF Context that pulls in the tables that I need (Categories and Projects) for this application. I put that model in a folder called "Data". This is just the convention that I'm using. Others like to place their data access layer in a completely different project. Do what makes you happy.

Translating Data To ViewModels

I always take the data from the EF Model and put it directly into a model class that I defined. This class is simple and more importantly, easy for .NET to serialize to different formats. This sort of a class is commonly called a ViewModel.

I create a Models folder and create a ViewModel for a Product.

Product ViewModel

public class Product {
  public int ProductId { get; set; }
  public string ProductName { get; set; }
  public int? SupplierId { get; set; }
  public Category Category { get; set; }
  public string QuantityPerUnit { get; set; }
  public decimal? UnitPrice { get; set; }
  public short? UnitsInStock { get; set; }
  public short? UnitsOnOrder { get; set; }
  public short? ReorderLevel { get; set; }
  public bool Discontinued { get; set; }
}

Notice how some fields are nullable? This is because the field they will eventually be mapped to in the database is nullable as well, and EF maps these nullable database fields as nullable in the model.

Now we create a ViewModel for a category. Categories have products by way of a relationship. This is represented in the ViewModel by assigning a list of products the the category.

Category ViewModel

public class Category {
  public int CategoryId { get; set; }
  public string CategoryName { get; set; }
  public string CategoryDescription { get; set; }
  public byte[] Picture { get; set; }
  public IEnumerable<Product> Products { get; set; }
}

Data Access Code

I then create a Repositories folder. Here I house the classes that will be accessing the EF Model directly. This keeps me from having to reference the EF Model from my Controllers. It's generally a good idea to keep controller methods skinny, and push other logic into a different layer. Since we're just doing simple data retrieval here, the repository pattern suits us well.

I'll create a repository for the Categories table. Name the class CategoriesRepository.cs and place it in the Repositories folder.

Since all we need to show on the Home Screen is a list of Categories, the class can currently have one method which just returns a list of all the Categories, mapped to ViewModel objects.

The Categories Repository

public class CategoriesRepository {

  readonly Data.NorthwindEntities _entities = new Data.NorthwindEntities();

  public IQueryable<models.category /> Get() {
    var categories = _entities.Categories.Select(c =>
      new Models.Category {
        CategoryId = c.Category_ID,
        CategoryName = c.Category_Name,
        CategoryDescription = c.Description,
        Picture = c.Picture,
        Products = c.Products.Select(p =>
          new Models.Product {
            ProductId = p.Product_ID,
            Discontinued = p.Discontinued,
            ProductName = p.Product_Name,
            QuantityPerUnit = p.Quantity_Per_Unit,
            ReorderLevel = p.Reorder_Level,
            SupplierId = p.Supplier_ID,
            UnitPrice = p.Unit_Price,
            UnitsInStock = p.Units_In_Stock,
            UnitsOnOrder = p.Units_On_Order
          })
      });

      return categories;
  } 
}

A Quick Note On IEnumerable vs IQueryable: Have you ever wondered why sometimes people return an IQueryable, sometimes an IEnumerable (as above) and sometimes an IList or even List? I sure did. How many types could we possibly need here? It's because IQuerable's are executed in the database. IEnumerable's (and implementing types like List) do it in memory. We try to use IQueryable when doing database queries so that the database gets leveraged for what it's good at and we aren't doing intensive data manipulation operations in memory. For more information on IQueryable vs IEnumerable, see this stack overflow thread.

Home View

With all of our data plumbing out of the way (for now), we can finally create our first view. Create a Home Controller of type Empty MVC Controller. The Index method simply needs to return a matching MVC View and we'll retrieve the Categories from the database to send along as the model.

HomeController Index Method

public class HomeController : Controller
{
  readonly Repositories.CategoriesRepository _categories = new Repositories.CategoriesRepository();

  public ActionResult Index() {

      var categories = _categories.Get();

      return View(categories);
  }
}

Ideally, we would want to inject the repository and EF dependencies in this project into their respective classes via constructor methods and IOC containers. For the sake of simplicity in demonstration I have omitted architectural concepts that might interfere with the main point of building a mobile web app.

Now create a Home folder under Views and add in a new MVC View. You can choose the "Empty" scaffold template, name it Index and have it use the Shared\_Layouts.cshtml as the Layout page. You can also select to make it a strongly typed view with the Model class being the Category ViewModel.

Visual Studio will generate us a new MVC view. It's got the layout page defined and the Category ViewModel specified at the top as the model.

Generated Home View

@model NorthwindMobile.Models.Category

@{
  ViewBag.Title = "Index";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>

This view is going to be listing categories, so change the @model definition to be an IEnumerable of categories. That's what the HomeController will be passing.

We can also remove the <h2> tag and add in the markup for a Kendo UI Mobile view. The view is currently empty, and that's OK.

Home View With Kendo UI Mobile View

@model IEnumerable<NorthwindMobile.Models.Category>

@{
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div data-role="view" data-layout="main" data-title="Home" id="home">
  I'm The Home View
</div>

Notice that a Kendo UI Mobile view is just a div with its data-role set to view. Also notice that we have assigned it to the main layout. That is the layout that we created in the _Layout.cshtml page.

Now we are ready to actually create the Kendo UI Mobile application with 1 single magical method. Open a script tag right before the closing <body> tag in _Layout.cshtml and create a new Kendo UI Mobile Application.

Create A New Kendo UI Mobile Application

<script>
  // create a new kendo ui mobile application using
  // the whole page. use the 'flat' skin and server navigation.
  new kendo.mobile.Application(document.body, { 
    skin: "flat",
    serverNavigation: true 
  });
</script>

That one line creates the mobile application. You can fire this up in the browser and see it work. It's not terribly impressive just yet, but we're thanks to our database plumbing work, we're perfectly poised to add some features.

Before we do that, a quick note from our sponsor on server navigation.

Server Navigation

By default, Kendo UI Mobile operates as a SPA. That is, it expects all the views to either be in the page, or loaded via AJAX. It has it's own router and expects that a postback will never occur. This is because there is nothing to post back to in environments like PhoneGap. It also allows Kendo UI Mobile to mimic the look and feel of the native OS with view animations.

By toggling serverNavigation: true, we have asked Kendo UI Mobile not to load remote views via AJAX. This will cause Kendo UI Mobile to act like a rather standard web application.

Settings View

Add a Settings Controller and just have it return the view.

SettingsController.cs

public class SettingsController : Controller
{
  //
  // GET: /Settings/

  public ActionResult Index()
  {
      return View();
  }
}

Then add it's corresponding view by creating a Settings folder and a new empty MVC View that uses the _Layouts.cshtml layout page. Create a new Kendo UI Mobile View and assign it the main layout just like we did with the home view.

Settings View

@{
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div data-role="view" data-title="Settings" id="settings" data-layout="main">
  I'm Settings!
</div>

If you run the application now, you can toggle between the Kendo UI Mobile views by hitting the Tabstrip buttons.

We have a problem though. Did you pick up on it? When the user clicks on the "Settings" tab, the browser is redirected to the Settings view, but the Tabstrip doesn't update.

Manually Controlling Navigation State

Since we asked Kendo UI Mobile to make this a server operation, it is no longer controlling the routing of paths and views. It's simply loading whatever view is in the page when the URL is called. The server is building those views and delivering them statically. Kendo UI Mobile has no way of knowing which tab we want it to display since it's not controlling the views anymore. In absence of that information, it displays the "Home" tab every time.

What we need to do is to manually switch the tab to the correct one based on which view we are in. There are many ways to pass this information. We could put it in the ViewBag and pass it from the server. I like to do this client-side with markup. I believe that HTML should define the behaviour of HTML when possible.

The way I like to control this is by storing the tab for the view as a data attribute, and then calling the switchTo method of the Tabstrip.

Let me show you how this works.

The Kendo UI Tabstrip has a switchTo method that matches on the href. That means that if I want to switch to a tab with an href of home or /home, I just need to call switchTo('home').

First, we assign the attribute which tracks tab state to both the Home and Settings view. I use the data-switch-to attribute since it matches the method name we'll be using.

Storing Tab State In The View Markup

@model IEnumerable<NorthwindMobile.Models.Category>

@{
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<div data-role="view" id="home" data-title="Categories" data-layout="main" data-switch-to="home">
  I'm The Home View
</div>

Add the same attribute to the Settings view.

All that's left to do now is retrieve that value in the layout and call the switchTo method on the Tabstrip. In order to call that method, we have to get a reference to the Tabstrip. In order to get the reference, we need to make sure we do all of this after the mobile application is initialized by Kendo UI. Timing is everything.

When a Kendo UI Mobile Application is initialized, it fires an init event after it's all finished creating the app. We can define a function for that event and do the tab switching there.

Define Application Init Event

<script>
new kendo.mobile.Application(document.body, {
  skin: "flat",
  serverNavigation: "true",
  init: function () {
      // tab switching happens here
  }
});
</script>

In order to get the data-switch-to attribute from the current view (whatever that may be), we can select any items in the page with a data-role of view. This is just plain jQuery. Then we can look for the showIn data value which maps to the data-show-in attribute. I also indexed the role selector in case we end up with multiple views on a page. In that case, the first one will win.

If the view has a value for data-switch-to, we can get a reference to the Tabstrip by selecting it by it's role (tabstrip), and then passing "kendoMobileTabStrip" to the data method. All widgets store their instance inside the element's data API. This is per jQuery widget creation guidelines.

Once we have the widget instance, we just call showIn with the value we got from the view. All of that boils down to just two simple lines of code.

Tab Switching Code

<script>
new kendo.mobile.Application(document.body, {
  skin: "flat",
  serverNavigation: "true",
  init: function () {
    // ** this switches the tabstrip to the right view **
    // get the current view's id
    var tabState = $("[data-role='view']").data("switchTo");
        // tell the tabstrip to switch to that item
    if (tabState) {
        $("[data-role='tabstrip']").data("kendoMobileTabStrip").switchTo(tabState);
    }
  }
});
</script>

Now the appropriate tab is highlighted when we switch between views. Very nice!

Adding Categories

So far we haven't added in the data that we worked so hard to wire up. Let's do that now.

ListViews And Mobile UX Paradigms

User Experience is different on mobile. It just is. Certain types of common UI patterns - like grids for instance - work great on a desktop, but are extremely difficult to implement properly on a mobile device. Fingers are fat and they obscure the screen. This is why we have come up with different ways of displaying and navigating through data. One of the most common patterns for displaying a collection of data, is to use a ListView.

Many applications implement a ListView of some sort. This is done across all platforms and all OS's, but was made famous by Apple when they added the momentum scrolling. If you now scroll a list of items on a mobile device that does not have a bouncy feel to it, you can tell right away and it feels extremely odd.

Kendo UI Mobile has a ListView widget and it automatically implements momentum scrolling for you.

Adding A ListView For Categories

Since we are already returning a list of categories as the model for the Home view, it's easy to add a ListView widget in and populate it with data from the server. And since we're building a mobile web site the good old fashioned way, all we need to do is iterate over the model using Razor and a foreach loop. Kendo UI Mobile ListViews are really just an unordered list (<ul>) at their core, so we can build one up using that HTML element. All we have to do to cause Kendo UI to turn the plain <ul> into a Kendo UI Mobile ListView, is to give it a data-role of listview.

Add ListView Of Categories To Home View

<div data-role="view" id="home" data-title="Categories" data-layout="main" data-switch-to="home">

  <ul data-role="listview">
    @foreach (var item in Model) {
      <li>
        <a href="#">
          <h1>@item.CategoryName</h1>
          <p>
            @item.CategoryDescription
          </p>
        </a>
      </li>
    }
  </ul>

</div>

This populates the page with categories from the database on the server, and then transforms it into a Kendo UI Mobile ListView on the client.

Allowing Users To Drill Down

If we were on a desktop, we could have a grid of categories, and then expand a category to see it's specific products, and then put a grid row into edit mode to edit a product. On mobile, this is not really an option. We can implement the same functionality, but we have to be a bit smarter about how its done and think a little bit differently.

We will do just that in part two of this article where we implement navigation for a data hierarchy.

If you have been following along, you can check out my progress so far, and of course grab the code from the GitHub repo. You can always grab a trial of Kendo UI at any time.

Until next time, just ponder this: The postback is far from dead. It's far too often dismissed and remains a powerful tool at your disposal.


Burke Holland is the Director of Developer Relations at Telerik
About the Author

Burke Holland

Burke Holland is a web developer living in Nashville, TN and was the Director of Developer Relations at Progress. He enjoys working with and meeting developers who are building mobile apps with jQuery / HTML5 and loves to hack on social API's. Burke worked for Progress as a Developer Advocate focusing on Kendo UI.

Comments

Comments are disabled in preview mode.