Telerik blogs

On my last visit to the SPA, I introduced the new kendo.View and showed some of the use cases and API calls for it. This second visit will include a weekend package with a room, and a relaxation session with DOM replacement therapy. I'll introduce the kendo.Layout and show how it enhances the massage techniques of the kendo.View.

A Room With A View

Most server side HTML rendering engines allow some form of layout to be used - whether it's called a "Master Page", a "Layout" or is simply a set of include files. The page layout is what gives the page its core structure - the header, the footer and the common elements for the site, such as company name and logo. Individual pages then come along and fill in the placeholders and empty parts of the layout with the content that the individual page needs. The end result is a complete page that has a consistent look and feel. This is pretty basic stuff for back-end web servers. Fortunately, it's also pretty basic when it comes to building Single Page Apps in the browser, too.

The kendo.Layout inherits from kendo.View directly, so it includes all of the functionality of a view. It also provides one very important addition: the showIn method. This is the method that provides the ability to place new content in to the placeholders or empty elements of a page. It allows content to be swapped out when needed, and new content to be pushed in.

DOM Replacement Therapy

The Layout itself needs a template to render - this is the same type of template that a View uses, since the Layout inherits from View. The only difference between the Layout's template and a View template is that the Layout template will likely have some empty DOM elements to use as placeholders.

The content that is pushed in to the Layout's placeholder(s) is another View. With multiple placeholders in a given Layout, multiple views can be pushed in to it. For example, the kitteh gallery that I started working on in the last post can be layed out in a more complete page at this point:

<!-- define a template for the layout -->
<script id="layout-template" type="text/x-keno-template">
  <h1>Muh Kittehz!</h1>
  <div id="kitteh-list"></div>
  <div id="kitteh"></div>
  <p>Teh kittehs are the bestest! I want to hug them all!</p>
</script>

<!-- define templates for all the views -->

<script id="kitteh-list-template" type="text/x-kendo-template">
  <div data-role="listview" data-bind="source: imageSource" data-template="kitteh-list-item-template"></div>
</script>

<script id="kitteh-list-item-template" type="text/x-kendo-template">
  <img data-bind="attr: {src: url}" height="100" width="150">
</script>

<script id="kitteh-view-template" type="text/x-keno-template">
  <h3 data-bind="text: name"></h3>
  <img data-bind="attr: {src: url}">
</script>

<!-- a div to place everything in to the page -->
<div id="main"></div>

With these templates in place, the Layout can be rendered in to an existing DOM element ("#main" in this case) and then the individual views can be rendered in to the placeholders.

// render a layout in to the "#main" element
var layout = new kendo.Layout("layout-template");
layout.render("#main");

// render a list of kittehz in to the "#kitteh-list" element
var kittehSource = new kendo.data.DataSource({
  data: [
    {id: 1, name: "Fuzzball", url: "http://placekitten.com/300/200"},
    {id: 2, name: "Kitteh", url: "http://placekitten.com/301/200"},
    {id: 3, name: "Nuther", url: "http://placekitten.com/300/201"},
    {id: 4, name: "Cutezee", url: "http://placekitten.com/301/201"}
  ],
      
  schema: {
    model: { id: "id", fields: { url: "string" } }
  }
});

var kittehModel = kendo.observable({
    imageSource: kittehSource
});

var kittehListView = new kendo.View("#kitteh-list-template", {
  model: kittehModel
});
layout.showIn("#kitteh-list", kittehListView);

// render a single kitteh view in to the "#kitteh" element
var kitteh = kendo.observable({
  name: "Fuzzball",
  url: "http://placekitten.com/300/200"
});

var kittehView = new kendo.Layout("kitteh-view-template", {
  model: kitteh
});
layout.showIn("#kitteh", kittehView);

The end result is a page layout with a kitteh view stuff in to it:

Mud Masks And Moisturizing

Layouts are a welcome addition to the SPA. They provide the ability to replace the contents of a given area of the DOM with that of another View instance. This lets the page have a consistent layout around the outside of the content that is changing, and allows the content to change without having to completely re-render the entire screen.

But just because we can replace the View in a given Layout element, doesn't mean we should.

For example, if I wanted to make the image list above clickable, I would not want to replace the entire kitteh-view with yet another instance of a view that renders the same template. This would be a waste of resources in both JavaScript (standing up a new View object) and in the DOM (replacing DOM elements with the same elements). Instead, I should use the power of data-binding to just replace the current image that is being displayed within the kitteh-view.

To do this, I just need to update the observable view model that the kitteh-view is bound to and it will show the new kitteh image correctly.

I'll make the image list selectable by updating the template:

<script id="kitteh-list-template" type="text/x-kendo-template">
  <div data-role="listview" data-bind="source: imageSource, events: {change: imageClicked}" data-selectable="true" data-template="kitteh-list-item-template"></div>
</script>

And then I'll change the JavaScript so that when an image is clicked (selected), it updates the "kitteh" view model. This will, in turn, update the currently displayed kitty.

var kittehModel = kendo.observable({
  imageSource: kittehSource,
    
  imageClicked: function(e){
    // get the selected image
    var index = e.sender.select().index();
    var image = this.imageSource.view()[index];

    // update the "kitteh" view model
    kitteh.set("name", image.get("name"));
    kitteh.set("url", image.get("url"));
  }
});

Now when I click a kitteh, it shows the right one in the main view.

The times where it would make sense to completely replace a View within a Layout are when the DOM structure in the Layout needs to be changed more dramatically. For example, if I were going to switch from a kitteh-view to an add-edit form, I would build a separate View to manage the form. When it came time to show the form in the main content area, I would replace the "#kitten" contents by calling the layout.showIn method and supplying the add-edit View as the view to display.

Advanced Age Defying Skin Therapy

The introduction of a kendo.Layout begins to show the true path of a Single Page Application. Now I can not only render a view on to the screen, but I can separate the various parts of my screen with different views and view-models. I can then compose those views in to a larger application structure - a layout.

There are a lot more pieces to building a large-scale Single Page Application, of course. Moving beyond a simple list and view structure in to something that needs more moving parts, has more views to display and needs any kind of workflow, will need more code and more coordination. I haven't even mentioned the need to bookmark an image and get back to it from a browser refresh or link from an external site, either. Stay tuned for more on these concepts, though. I'll be continuing my "Day At The Spa" series in the coming weeks.

Treat Yourself To A Day At The SPA!

Interested in seeing what Kendo UI can do for you and your project? Want to try out the latest and greatest in the Single Page Application structures that Kendo UI provides? Head over to the download page, and start working with Kendo UI today!


About the Author

Derick Bailey

About the Author
Derick Bailey is a Developer Advocate for Kendo UI, a developer, speaker, trainer, screen-caster and much more. He's been slinging code since the late 80’s and doing it professionally since the mid 90's. These days, Derick spends his time primarily writing javascript with back-end languages of all types, including Ruby, NodeJS, .NET and more. Derick blogs atDerickBailey.LosTechies.com, produces screencasts atWatchMeCode.net, tweets as @derickbailey and provides support and assistance for JavaScript, BackboneJS,MarionetteJS and much more around the web.

Comments

Comments are disabled in preview mode.