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!