MVC 4, Kendo UI, SPA with Layout, View, Router & MVVM

This will be part three of a six part series of blog posts.

  1. Modern Web Application Layered High Level Architecture with SPA, MVC, Web API, EF, Kendo UI, OData
  2. Generically Implementing the Unit of Work & Repository Pattern with Entity Framework in MVC & Simplifying Entity Graphs
  3. MVC 4, Kendo UI, SPA with Layout, View, Router & MVVM
  4. MVC 4, Web API, OData, EF, Kendo UI, Grid, Datasource (CRUD) with MVVM
  5. MVC 4, Web API, OData, EF, Kendo UI, Binding a Form to Datasource (CRUD) with MVVM
  6. Upgrading to Async with Entity Framework, MVC, OData AsyncEntitySetController, Kendo UI, Glimpse & Generic Unit of Work Repository Framework v2.0

Update: 09/09/2013 – Project has been uploaded to CodePlex: https://genericunitofworkandrepositories.codeplex.com, updated Visual 2013, Twitter Bootstrap, MVC 5, EF6, Kendo UI Bootstrap theme, project redeployed to Windows Azure Website.

Update: 06/20/2013 – Bug fix(es): Fixed View being loaded duplicate times. Enhancement(s): Added View caching. Updated blog, sample app download, and live demo

Wondering how to setup a SPA with MVC 4 project using Kendo UI Web…?! Well let’s cut to the chase and get started. We will start off with a plain old regular ASP.NET MVC 4 Internet project template and convert to a SPA, for the most part this implementation will keep in mind many of us are familiar with MVC 4 so we’ll try to adapt a lot things we are intimate with like the usage and organization of views, layouts, conventions, etc.

This will be part one five of a five part series of blog posts.

  1. Generically Implementing the Unit of Work & Repository Pattern with Entity Framework in MVC & Simplifying Entity Graphs
  2. MVC 4, Kendo UI, SPA with Layout, View, Router & MVVM
  3. MVC 4, Web API, OData, EF, Kendo UI, Grid, Datasource (CRUD) with MVVM
  4. MVC 4, Web API, OData, EF, Kendo UI, Binding a Form to Datasource (CRUD) with MVVM
  5. Upgrading to Async with Entity Framework, MVC, OData AsyncEntitySetController, Kendo UI, Glimpse & Generic Unit of Work Repository Framework v2.0

Taking a look at a high level architecture of this three part series blog: Modern Web Application Layered High Level Architecture with SPA, MVC, Web API, EF, Kendo UI.

Live demo: http://longle.azurewebsites.net.

You’ll need KendoUIWeb NuGet package.

6-18-2013 1-40-51 AM

First let’s create the SPA landing page (index.html), this will be the default page when the site is loaded up and where our Kendo UI Layout object will reside, and where we will swap our different views in.

Index.html


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>MVC 4 SPA</title>
    <link href="/Content/kendo/2013.1.319/kendo.common.min.css" rel="stylesheet" />
    <link href="/Content/kendo/2013.1.319/kendo.metro.min.css" rel="stylesheet" />
    <link href="/Content/Site.css" rel="stylesheet" />
    <script src="/Scripts/jquery-2.0.2.min.js"></script>
    <script src="/Scripts/kendo/2013.1.319/kendo.web.min.js"></script>
    <script>
        var templateLoader = (function ($, host) {
            return {
                loadExtTemplate: function (name, path) {
                    $.ajax({
                        async: false,
                        url: path,
                        cache: false,
                        success: function (result) {
                            $("body").append(result);
                        },
                        error: function (result) {
                            alert("Error Loading View/Template -- TODO: Better Error Handling");
                        }
                    });
                }
            };
        })(jQuery, document);

        $(function () {
            var views = {};
            templateLoader.loadExtTemplate("layout", "/content/views/layout.html");
            var layout = new kendo.Layout($('#layout').html());
            layout.render($("#app"));

            var router = new kendo.Router();
            var addRoute = function (route, name, path, forceRemoteLoad) {
                forceRemoteLoad = typeof forceRemoteLoad !== "undefined" ? forceRemoteLoad : false;
                router.route(route, function () {
                    kendo.fx($("#body")).slideInRight().reverse().then(function () { // transition, slide view left
                        var isRemotelyLoaded = false;
                        if (views[name] == null || forceRemoteLoad)
                        {   // check if we have already loaded in cache, could store this in browser local storage for larger apps
                            isRemotelyLoaded = true;
                            templateLoader.loadExtTemplate(name, path); // load the view
                            views[name] = new kendo.View(('#' + name)); // add the view to cache
                        }
                        layout.showIn("#body", views[name]); // switch view
                        $(document).trigger("viewSwtichedEvent", { route: route, name: name, path: path, isRemotelyLoaded: isRemotelyLoaded }); // publish event view has been loaded (EventAggregator pattern)
                        kendo.fx($("#body")).slideInRight().play(); // transition, slide view back to the right (center)
                    });
                });
            };

            addRoute("/", "home", "/content/views/home.html");
            addRoute("/about", "about", "/content/views/about.html");
            addRoute("/contact", "contact", "/content/views/contact.html");
            addRoute("/categories", "categories", "/content/views/categories.html");
            addRoute("/customers", "customers", "/content/views/customers.html");
            addRoute("/products", "products", "/content/views/products.html");
            addRoute("/productEdit/:id", "productEdit", "/content/views/productEdit.html");

            router.start();
        });
    </script>
</head>
<body>
    <div id="app"></div>
</body>
</html>

I’ve deliberately left much of the JavaScript code on each of the pages in the interest of easily understanding what’s happening on each of the pages or views, obviously you can extract them into their own .js files however you see fit.

TemplateLoader Helper


        var templateLoader = (function ($, host) {
            return {
                loadExtTemplate: function (name, path) {
                    $.ajax({
                        async: false,
                        url: path,
                        cache: false,
                        success: function (result) {
                            $("body").append(result);
                        },
                        error: function (result) {
                            alert("Error Loading View/Template -- TODO: Better Error Handling");
                        }
                    });
                }
            };
        })(jQuery, document);

The templateLoader helper method was used from here, and has been slightly modified so that we can load Kendo Views remotely from the server in our SPA when navigating through the application.

  1. It’s taking a path to a file
  2. Grabbing the contents with jQuery Ajax
  3. Appending the contents to the body of our document
  4. Then notifying the application that the template has loaded

Kendo UI Web Router


        $(function () {
            var views = {};
            templateLoader.loadExtTemplate("layout", "/content/views/layout.html");
            var layout = new kendo.Layout($('#layout').html());
            layout.render($("#app"));

            var router = new kendo.Router();
            var addRoute = function (route, name, path, forceRemoteLoad) {
                forceRemoteLoad = typeof forceRemoteLoad !== "undefined" ? forceRemoteLoad : false;
                router.route(route, function () {
                    kendo.fx($("#body")).slideInRight().reverse().then(function () { // transition, slide view left
                        var isRemotelyLoaded = false;
                        if (views[name] == null || forceRemoteLoad)
                        {   // check if we have already loaded in cache, could store this in browser local storage for larger apps
                            isRemotelyLoaded = true;
                            templateLoader.loadExtTemplate(name, path); // load the view
                            views[name] = new kendo.View(('#' + name)); // add the view to cache
                        }
                        layout.showIn("#body", views[name]); // switch view
                        $(document).trigger("viewSwtichedEvent", { route: route, name: name, path: path, isRemotelyLoaded: isRemotelyLoaded }); // publish event view has been loaded (EventAggregator pattern)
                        kendo.fx($("#body")).slideInRight().play(); // transition, slide view back to the right (center)
                    });
                });
            };

            addRoute("/", "home", "/content/views/home.html");
            addRoute("/about", "about", "/content/views/about.html");
            addRoute("/contact", "contact", "/content/views/contact.html");
            addRoute("/categories", "categories", "/content/views/categories.html");
            addRoute("/customers", "customers", "/content/views/customers.html");
            addRoute("/products", "products", "/content/views/products.html");
            addRoute("/productEdit/:id", "productEdit", "/content/views/productEdit.html");

            router.start();
        });

We are also putting the Kendo UI Router to good use so that we can navigate between the different views in our SPA while syncing with the browser history so even though we are never refreshing, and our app never does any post backs, the user is still able to navigate back and forward using their browser buttons.

We can see that we are also using the Kendo FX API, this is to polish the UX in our SPA by adding slide transitions when swapping views. We are simply remotely loading the requested View (if it hasn’t already been loaded for the first time) from the server, sliding the #body div to the left, swapping the View with the requested one, sliding the #body div back it’s place (you can click on the live demo link to see this in action). If the view has already been loaded we cache the view in a dictionary, the next time this View is navigated to, we will check cache it it already exist then will load it from there, if not, we’ll load it from the server. Yes, we could have done the transitions this with a jQuery plug-in or some other tool or framework, however the intent was here was to accomplish this (along with Part 2 and 3 of this blog series) with the use of only framework, Kendo UI Web.

addRoute Helper


            var addRoute = function (route, name, path, forceRemoteLoad) {
                forceRemoteLoad = typeof forceRemoteLoad !== "undefined" ? forceRemoteLoad : false;
                router.route(route, function () {
                    kendo.fx($("#body")).slideInRight().reverse().then(function () { // transition, slide view left
                        var isRemotelyLoaded = false;
                        if (views[name] == null || forceRemoteLoad)
                        {   // check if we have already loaded in cache, could store this in browser local storage for larger apps
                            isRemotelyLoaded = true;
                            templateLoader.loadExtTemplate(name, path); // load the view
                            views[name] = new kendo.View(('#' + name)); // add the view to cache
                        }
                        layout.showIn("#body", views[name]); // switch view
                        $(document).trigger("viewSwtichedEvent", { route: route, name: name, path: path, isRemotelyLoaded: isRemotelyLoaded }); // publish event view has been loaded (EventAggregator pattern)
                        kendo.fx($("#body")).slideInRight().play(); // transition, slide view back to the right (center)
                    });
                });
            };

The addRoute is simply a helper method to register our routes and the with the Router along with the delegate we want invoke when navigating between our Views. Our delegate simply handles the animation transitions, switching out the Views and caching of our Views.

Now our next step is just converting the regular ASP.NET views to pure html which is pretty straight forward. For now, since MVC ignores routes for anything under /Content folder, we’ll just put our views in Spa/Content/views/, you can place them anywhere you see fit, and just have the MVC runtime ignore that path using the routes.IgnoreRoute([path-goes-here]) method in your RoutConfig.cs.

6-17-2013 10-41-19 PM

Spa/Content/views/layout.html


<script type="text/x-kendo-template" id="layout" highlight="31">
    <header>
        <div class="content-wrapper">
            <div class="float-left">
                <p class="site-title"><a href="/">CBRE Architecture & Design Team</a></p>
            </div>
            <div class="float-right">
                <section id="login">
                    <ul>
                        <li><a href="/Account/Register" id="registerLink">Register</a></li>
                        <li><a href="/Account/Login" id="loginLink">Log in</a></li>
                    </ul>
                </section>
                <nav>
                    <ul id="menu">
                        <li><a href="#/" >Home</a></li>
                        <li><a href="#/about" >About</a></li>
                        <li><a href="#/contact">Contact</a></li>
                    </ul>
                </nav>
                <nav>
                    <ul id="menu">
                        <li><a href="#/customers" >Customers</a></li>
                        <li><a href="#/categories" >Categories</a></li>
                        <li><a href="#/products" >Products</a></li>
                    </ul>
                </nav>
            </div>
        </div>
    </header>
    <div id="body">
    </div>
    <footer>
        <div class="content-wrapper">
            <div class="float-left">
                <p>&copy; 2013 - My ASP.NET MVC Application</p>
            </div>
        </div>
    </footer>
</script>

The layout.html View is loaded first, this is pretty much the layout of the application, all the Views will be loaded into the div:

<div d="body">

Spa/Content/views/home.html


<script type="text/x-kendo-template" id="home">
<section class="featured">
    <div class="content-wrapper">
        <hgroup class="title">
            <h1>Home Page.</h1>
            <h2>Modify this template to jump-start your ASP.NET MVC application.</h2>
        </hgroup>
        <p>
            To learn more about ASP.NET MVC visit
                <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
                The page features <mark>videos, tutorials, and samples</mark> to help you get the most from ASP.NET MVC.
                If you have any questions about ASP.NET MVC visit
                <a href="http://forums.asp.net/1146.aspx/1?MVC" title="ASP.NET MVC Forum">our forums</a>.
        </p>
    </div>
</section>

<section class="content-wrapper main-content clear-fix">

    <h3>We suggest the following:</h3>
    <ol class="round">
        <li class="one">
            <h5>Getting Started</h5>
            ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
        enables a clean separation of concerns and that gives you full control over markup
        for enjoyable, agile development. ASP.NET MVC includes many features that enable
        fast, TDD-friendly development for creating sophisticated applications that use
        the latest web standards.
        <a href="http://go.microsoft.com/fwlink/?LinkId=245151">Learn more…</a>
        </li>

        <li class="two">
            <h5>Add NuGet packages and jump-start your coding</h5>
            NuGet makes it easy to install and update free libraries and tools.
        <a href="http://go.microsoft.com/fwlink/?LinkId=245153">Learn more…</a>
        </li>

        <li class="three">
            <h5>Find Web Hosting</h5>
            You can easily find a web hosting company that offers the right mix of features
        and price for your applications.
        <a href="http://go.microsoft.com/fwlink/?LinkId=245157">Learn more…</a>
        </li>
    </ol>

</section>
</script>
<script>
    var homeModel = new kendo.data.ObservableObject({});
</script>

Spa/Content/views/contact.html


<script type="text/x-kendo-template" id="contact">
<section class="content-wrapper main-content clear-fix">
    <hgroup class="title">
        <h1>Contact.</h1>
        <h2>Your contact page.</h2>
    </hgroup>

    <section class="contact">
        <header>
            <h3>Phone</h3>
        </header>
        <p>
            <span class="label">Main:</span>
            <span>425.555.0100</span>
        </p>
        <p>
            <span class="label">After Hours:</span>
            <span>425.555.0199</span>
        </p>
    </section>

    <section class="contact">
        <header>
            <h3>Email</h3>
        </header>
        <p>
            <span class="label">Support:</span>
            <span><a href="mailto:Support@example.com">Support@example.com</a></span>
        </p>
        <p>
            <span class="label">Marketing:</span>
            <span><a href="mailto:Marketing@example.com">Marketing@example.com</a></span>
        </p>
        <p>
            <span class="label">General:</span>
            <span><a href="mailto:General@example.com">General@example.com</a></span>
        </p>
    </section>

    <section class="contact">
        <header>
            <h3>Address</h3>
        </header>
        <p>
            One Microsoft Way<br />
            Redmond, WA 98052-6399
        </p>
    </section>
</section>
</script>
<script>
    var contactModel = new kendo.data.ObservableObject({});
</script>

Spa/Content/views/about.html


<script type="text/x-kendo-template" id="about">
<section class="content-wrapper main-content clear-fix">
    <hgroup class="title">
        <h1>About.</h1>
        <h2>Your app description page.</h2>
    </hgroup>

    <article>
        <p>
            Use this area to provide additional information.
        </p>

        <p>
            Use this area to provide additional information.
        </p>

        <p>
            Use this area to provide additional information.
        </p>
    </article>

    <aside>
        <h3>Aside Title</h3>
        <p>
            Use this area to provide additional information.
        </p>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/Home/About">About</a></li>
            <li><a href="/Home/Contact">Contact</a></li>
        </ul>
    </aside>
</section>
</script>
<script>
    var aboutModel = new kendo.data.ObservableObject({});
</script>

We see that each and every View is responsible for the Model that it will use and bind to, so every view will need to have a Model. The convention we are using here is name of View and viewModel, e.g. so if your View is name Product then it should have a model named ProductModel. The code in the SPA/Index.html will handle binding them together, we just need to follow the convention and everything else is handled.

For live demo: http://longle.azurewebsites.net

Download sample application: https://genericunitofworkandrepositories.codeplex.com

Stay tune for Part 2 and 3…

Part 2 – MVC 4, Web API, OData, EF, Kendo UI, Grid, Datasource with MVVM
Part 3 – MVC 4, Web API, OData, EF, Kendo UI, Binding a Form to Datasource (CRUD) with MVVM

Learning Kendo UI Web Development with MVC Book Published…!

Follow up on one of my previous blog post in regards to Kendo UI Web with MVC book project I had the opportunity to be involved with as a Technical Reviewer, the book is complete and has been published..! Kudos to John Adams (author) from RBA for all the late nights, weekends and hard work I know he put into the project.

For those of you looking for a good starting point, incorporating Kendo UI Web into your MVC project or solution the book has some good real world practical implementations with ASP.NET MVC.

Personally and professionally Kendo UI Web is my client side framework of choice. It’s one solution that offers it all, so that you don’t have into incorporate and include several different frameworks to gain some of the fundamental features of Kendo UI Web, especially when working with MVC.

My personal top favorite features of Kendo UI Web Framework

  • Widgets (client-side controls)
  • MVVM Framework (a must have for modern web apps)
  • Validation Framework
  • Templates
  • Built on top of jQuery
  • Custom UI/UX Themes
  • MVC 4 Sever Side Wrappers
  • SPA (Single Page App) Support (a must have for modern web apps)
  • Globalization
  • DataSource
  • List goes on…

http://www.amazon.com/dp/1849694346/?tag=packtpubli-20
http://www.packtpub.com/learning-kendo-ui-web-development/book
http://packtlib.packtpub.com/library/9781849694346

An easy-to-follow practical tutorial to add exciting features to your web pages without being a JavaScript expert with this book and ebook

Overview

Learn from clear and specific examples on how to utilize the full range of the Kendo UI tool set for the web
Add powerful tools to your website supported by a familiar and trusted name in innovative technology
Learn how to add amazing features with clear examples and make your website more interactive without being a JavaScript expert

In Detail

Creating useful and attractive web sites for today’s audiences requires more JavaScript programming than ever before. JavaScript, however, isn’t easy and staying up to date with recent trends makes it even harder. You need a way to integrate the latest technology into your web site without having to start from the beginning.

“Learning Kendo UI Web Development” shows you how to add the latest web features to your site without doing all of the work yourself. The experts at Telerik have created a fully supported code library that lets you focus on what makes your sites special while letting them focus on how that translates into cutting edge JavaScript code.

This book will take you on a survey through Kendo UI for the web from the basic widgets that wrap input fields to the full page scaffolding widgets for setting up your site.

Kendo UI for the web is a rich framework of JavaScript widgets and tools that will add immediate value to your web sites. Learn the full spectrum of what Kendo UI has to offer in specialized widgets that gather input from users by displaying calendars, sliders, or date pickers all the way up to widgets that structure your web pages through data-driven models in accordions, tabs, list views, and tree views.

“Learning Kendo UI Web Development” is the perfect companion for navigating the broad features offered by Telerik in JavaScript web development.

What you will learn from this book

  • Leverage data source objects and JavaScript templates with the TabStrip and Grid widgets
  • Guide users in date selection with the Calendar widget
  • Create fast and fluid word wheels with the AutoComplete widget and date selection with the Calendar widget
  • Take advantage of the powerful MVVM JavaScript architectural pattern
  • Take full HTML input from users with a graphical editor
  • Structure your site with the Menu and ListView widgets
  • Build interactive accordions with the PanelBar widget and a fun way to select numbers with the Slider widget
  • Organize your data with the Splitter and TreeView widgets and Customize pop-up windows and file uploads with the Window and Upload widgets

Approach

A practical tutorial with step-by-step example based approach.

Who this book is written for

This book is for web developers who want to take advantage of cutting edge JavaScript and HTML 5 web site features, but who don’t have the time or the knowledge to write all of that code by hand. The reader should be familiar with basic HTML 5 and JavaScript but does not need to be an expert.

Author:

John Adams currently works as an application development consultant in the Dallas/Fort Worth area for a fantastic company called RBA. He has been developing custom business applications with the Microsoft .NET platform for 6 years and has specialized in development with ASP.NET MVC. He loves writing code and creating solutions. Above all, he loves his wife and children and the lord Jesus Christ.

This book is dedicated to Michell, Samuel, and Sophie whose patience with my late nights made this project possible.

I would also like to thank RBA, especially my manager Will, who introduced me to the project and kicked everything off.

Finally, I would like to thank Kartikey Pandey, Anugya Khurana, Mayur Hule, Ricardo Covo, and Long Le for their oversight and editing skills. Their work has been exceptional and valuable throughout.

Reviewers:

Ricardo Covo has more than a decade of international experience in the Software Development field, with experience in Latin America, California, and Canada. He has a wealth of experience in delivering data-driven enterprise solutions across various industries.

With a Bachelor’s degree in Systems Engineering, complemented with a certification in Advanced Project Management, he has the right combination of technical and leadership skills to build development teams and set them up for efficient execution.

In 2007 he founded (and is the principal of) Web Nodes – Software Development (http://webnodes.ca); a custom software development company, with clients big and small in Canada, United States, and South America.

Prior to Web Nodes, Ricardo spent some years in the corporate world both in Canada and in the U.S., being part of companies such as Loblaws Inc., Trader Corporation, UNX (http://www.unix.com) and Auctiva (http://www.auctiva.com).

Ricardo’s passion for technology goes beyond work; he normally works on personal projects in an effort to always remain on top of the changes in technology. These projects include: http://ytnext.com, http://serversok.com, and http://toystrunk.com.

Long Le is a Principle .NET Architect and ALM Practitioner at CBRE. He also serves as consultant for Thinklabs and spends most of his time developing frameworks and application blocks, providing guidance for best practices and patterns, and standardizing the enterprise technology stack. He has been working with Microsoft technologies for over 10 years.

Le has focused on a wide spectrum of server-side and web technologies, such as ASP.NET Web Forms, ASP.NET MVC, Windows Workflow, LINQ and Entity Framework, DevExpress, and Kendo UI. In his spare time, he enjoys blogging (http://blog.longle.net) and playing Call of Duty on his XBOX. He’s recently became a proud father of his new born daughter Khloe Le. You can reach and follow him on Twitter @LeLong37.

Special thanks to my significant other Tina Le for all your love and support throughout this project and to my wonderful newborn daughter Khloe Le. I love you.

https://twitter.com/LeLong37/status/344402714240897024