Knock Me Out

Thoughts, ideas, and discussion about Knockout.js

Quick Tip: Reusing a Template by Passing Options in KnockoutJS

| Comments

Have you ever had the need to pass extra parameters to a template in addition to your data, so that you are able to reuse a single template for a variety of situations? Maybe you need to do some filtering, additional styling, or want to vary some of the text. Without passing this information to your template, you might have to create a number of very similar templates, bloated templates that include lots of branching, or pollute your data with information that is often only related to the UI.

The jQuery Templates plugin does support passing an options map to the .tmpl function. Current KnockoutJS code (after 1.12), now has the ability to pass the options map in the template binding using a templateOptions field.

The basic syntax looks like:

1
<div data-bind=“template: { name: items’, data: newItems, templateOptions: { header: New Items!”} }”></div>

In this example, you would then access the option using $item.header in your template code.

Sample

Suppose that your model contains menu items for breakfast, lunch, and dinner. You would like to render a section for each of these types of menu items, but use slightly different styles and header/footer information.

Let’s say our view model looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var viewModel = {
    breakfast: [
        {name: toast, price: 2.50},
        {name: pancakes, price: 4.00},
        {name: eggs, price: 3.25}],
    lunch: [
        {name: grilled cheese, price: 4.00},
        {name: hot dog, price: 3.50},
        {name: pizza, price: 6.00}],
    dinner: [
        {name: steak, price: 15.75},
        {name: fish, price: 11.00},
        {name: salad, price: 8.25}
    ],
};

ko.applyBindings(viewModel);

Along with showing the name and price of each item, we would like to have a custom header, footer, and apply some different styling to each section.

By passing templateOptions, we can have a single template that is able to render the different types of menu items.

1
2
3
<div data-bind=“template: { name: items’, data: breakfast, templateOptions: { header: Breakfast Items’, message: Wake up to these delicious items!’, class: breakfast } }”></div>
<div data-bind=“template: { name: items’, data: lunch, templateOptions: { header: Lunch Dishes’, message: Stop by for a quick lunch!’, class: lunch } }”></div>
<div data-bind=“template: { name: items’, data: dinner, templateOptions: { header: Dinner Entrees’, message: Enjoy our tasty dinner selections!’, class: dinner } }”></div>

Our template can then loop through our items and access the additional options that we passed to it. In this example, I am assuming that the items are not changing, so we are not using observables, using foreach on the template binding, or even setting up indvidual bindings in the template.

1
2
3
4
5
6
7
8
9
10
11
12
13
<script id=“items” type=“text/html”>
    <h3>${$item.header}</h3>
    <div class=${$item.class}>
        {{each $data}}
        <p>
            <span class=name>${name}</span>
            <span class=price>${price.toFixed(2)}</span>
        </p>
        {{/each}}
    </div>
    <p><em>${$item.message}</em></p>
    <hr />
</script>

The end result is a single, versatile template for displaying our items.

Warning

If you are passing templateOptions to the template binding from a nested template (so, specifying a template binding from within a template), then pay special attention to your syntax. You will encounter a problem, if your binding looks like this:

1
<div data-bind=“template: { name: items’, data: newItems, templateOptions: { header: New Items!”}}”></div>

The jQuery Templates plugin gets confused by the }} at the end of your binding, since that is part of its syntax. Adding a space between your braces will work fine. Hopefully this prevents someone from a little unnecessary frustration.

1
<div data-bind=“template: { name: items’, data: newItems, templateOptions: { header: New Items!”} }”></div>

Try it out here

Dynamically Changing Templates in KnockoutJS

| Comments

An interesting and useful feature that was recently added to KnockoutJS (after 1.12) is the ability to pass a function for the template name to the template binding. This has a few benefits and uses:

  • Allows you to render a section dynamically based on the state of your view model.
  • In a foreach situation allows you to even render individual items in your array with different templates
  • Keeps your templates small and reusable without needing too much conditional logic for rendering each situation

In a simple scenario, you may want a user to be able to toggle between a summary and details mode for viewing a list of articles.

Our view model might look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var viewModel = {
    articles: [{
        id: 1,
        title: "Article One",
        content: "Content for article one."},
    {
        id: 2,
        title: "Article Two",
        content: "Content for article two."},
    {
        id: 3,
        title: "Article Three",
        content: "Content for article three."}
                                               ],
    selectedView: ko.observable("summary"),
    selectedArticle: ko.observable()
};

In our data-binding, we set the selectedView observable based on some radio buttons. The name of the template to use no longer needs to be a string, instead we are able to bind it to the value of selectedView. Note: we return this in an anonymous function, because binding directly to an observable only works currently when we do not pass options as an object literal to the template binding., which we must do to pass foreach or data to the binding.

1
2
3
<input type="radio" name="choices" value="summary" data-bind="checked: selectedView" />Summary
<input type="radio" name="choices" value="details" data-bind="checked: selectedView" />Details
<div data-bind="template: { name: function() { return selectedView(); }, foreach: articles }"></div>

Now, we can easily toggle between summary and details modes. Typically, before we would have used a single template that had conditional logic for each view or used the visible binding to hide one or the other.

This gets a little more interesting when we start changing the template based on factors related to each item in the array. Suppose we also add an edit mode and track an observable for the selected article. Since, our logic is getting more complicated, let’s add a function that we can use to determine the template:

1
2
3
4
viewModel.selectedArticle = ko.observable();
viewModel.templateToUse = function(item) {
    return item === this.selectedArticle() ? edit : this.selectedView();
}.bind(viewModel);

Notice that the function takes in the data item as its first argument. Knockout passes the current item from its foreach loop to the function. Our binding now looks like:

1
<div data-bind="template: { name: templateToUse, foreach: articles }"></div>

Now, the articles are dynamically displayed in summary, details, or edit mode depending on the situation.

Try it out

jsFiddle to the Rescue!

| Comments

jsFiddle.net is an outstanding tool for sharing and collaborating on client-side development. Some key uses for it are:

  • Keeping a scrapbook of useful samples that you can access anywhere.
  • Sharing a sample of an issue that you are encountering. The exercise of reproducing the problem in its most simple form will often be enough to discover the issue on your own.
  • Sharing a potential answer to another person’s question in jsFiddle helps you gain a deeper understanding of their issue and helps you move past suggestions into actual working solutions.

Using KnockoutJS in jsFiddle

The documentation for jsFiddle describes the basics of how to use the site. Here are the steps that you need to follow to get KnockoutJS working in it:

  1. In the Choose Framework section choose a recent version of jQuery:
  2. In the Manage Resources section, add the other scripts that we need by entering a URL and hitting the plus icon. You will want to add them in the appropriate order listed. There are several locations to find hosted versions of these scripts, here are a couple of options for each:

    jQuery Templates plugin:

    Knockout:

    Mapping Plugin (if you need it):

    Should look like this:

  3. At this point you are ready to use KnockoutJS in your fiddle. Your HTML and jQuery Templates (enclosed in script tags) should go in the HTML pane. Your JavaScript can go in the JavaScript pane (without a script tag) and your style information can go in the CSS pane (without a style tag).

Forking/updating/Set as base

  • Use the Update button when you are happy with your code. This will save a copy of the code under an incrementing revision number appended to the address (/1 to start).
  • Use the Set as Base button to indicate that this revision should be loaded when the base address (no revision) of the fiddle is accessed.
  • Use the Fork button to create a new copy of this fiddle. Very useful when starting with someone else’s sample or when you want to use a past fiddle of your own as a base.

Base Fiddles

Here are a couple of basic fiddles that can easily be forked:

Other Features

Quick mention of a few other great features of jsFiddle.net:

  • TidyUp – this button will help format your code. It generally does a decent job of cleaning up JavaScript formatting, which can get messy if you are specifying complex object literals.
  • JSLint – this button will help verify that your JavaScript is valid. It is a bit hard to match up the reported line numbers with the actual code, but generally gives you a good idea where something is wrong. Definitely one of the first things to check if your code is not behaving properly.
  • Keyboard shortcuts – Ctrl+R runs it. Ctrl+S saves it. Ctrl up or down switches between the panes.
  • If you are a member, you can also easily access all of your past fiddles. For example, here is a list of all of mine: http://jsfiddle.net/user/rniemeyer/fiddles/

Support jsFiddle

I asked the other day if there was a way to support jsFiddle.net and was directed to a mousepad that you could order here, which I did. If you like the site, consider supporting them. Anyone else have other tips or tricks related to jsFiddle?

About Me

| Comments

I have been a software tester for the last 12 years. I have primarily worked with .NET based development and have spent the last few years working with an ASP.NET Web Forms application. I have a passion for software development. I enjoy reading tech blogs & books, listening to podcasts, doing tutorials, and watching videos from tech conferences to keep up on the latest and greatest in the dev world.

I started learning and using jQuery about three years ago and it seemed a bit revolutionary how it made client-side development so fun and easy. Recently, I started using the jQuery Templates plugin as well. As someone that used to love working with XML/XSL transform scenarios, I felt right at home sending JavaScript objects through these templates. Soon, I wanted all of my data to come as JSON via web service calls.

This seemed like a promising way to do some lighter weight client-side development on its own, until I started using KnockoutJS. I had heard about it first on this .NET Rocks episode and it seemed interesting, but not something that I had a need for at the time. I looked at it again, just before Steve Sanderson made an appearance on this Hanselminutes episode and gave it another shot.

KnockoutJS is the glue that I needed to really orchestrate the actions by jQuery and the jQuery Templates plugin. It was like a light bulb went off. Keeping the data layer separate on the client-side and watching your UI react to changes in this data is really a treat. I find the library to be very approachable, easy to understand, and customizable.

I have been spending some of my spare time trying to help people on the KO forums solve their issues. I always feel that the best way to learn a technology is to attempt to solve real problems with it. The forums have given me many of these problems in bite-size pieces to help learn the ins and outs of the library. I hope to continue participating in the forums regularly.

What do you like about KnockoutJS? Did you have that light bulb moment when you first started using it?

Introduction

| Comments

The primary focus of this blog is a JavaScript library called KnockoutJS that lets you write dynamic web user interfaces using the Model-View-View Model pattern. My goal is to learn and grow techinically, while generating discussion and awareness about this great library. Here are some of the topics that I plan to write about:

  • Patterns and techniques to get things done in KnockoutJS
  • Quick tips and discussion of lesser-known features
  • Exploring new functionality as it is added
  • Integrating KnockoutJS with other technologies
  • Comparison of KnockoutJS vs. other alternatives

I am interested in all types of feedback. If there are specific topics that you would like to see researched, please let me know (ryan-at-knockmeout.net)