Archive

Archive for September, 2012

Knockout and Custom Binding Providers

September 30, 2012 Leave a comment

Since I have such a strong background with XAML technologies, Knockout.js has been a natural fit for my development style. I really like the ability to program in a MVVM approach. Recently, I watched Ryan Neimeyer’s session he gave at the That Conference and I was really impressed with being able to create custom binding providers for Knockout.

When developing applications in XAML, I have always loved using Caliburn.Micro as I found Rob Eisenberg’s implementation of convention over configuration to be a great time saver and value add when trying to build applications quickly. Well, with that said, I wanted to create a simple version that would facilitate using conventions but also allow you to provide your own data-bind statements when you wanted to as well.

Before we jump over to my sample on jsFiddle, I wanted to walk you through the simple rules that I have put in place. First of all, I wanted my code to be a minimalistic as possible.

I tried using the name attribute of an element but it turns out that not all DOM children expose the name attribute. With that, I decided to go with use the data-name attribute that is supported with HTML5.

The following link is a sample test page on jsFiddle that demonstrates my solution.

I will walk you through the code required to build my custom binding provider for Knockout.js.

//knockout-conventionBindingProvider v0.0.11 | (c) 2012 Matt Duffield | http://www.opensource.org/licenses/mit-license
!(function (factory) {
    //AMD
    if (typeof define === "function" && define.amd) {
        define(["knockout", "exports"], factory);
        //normal script tag
    } else {
        factory(ko);
    }
}(function(ko, exports, undefined) {
    //a bindingProvider that uses something different than data-bind attributes
    //  options - is an object that can include "attribute" and "valueUpdate" options
    //    "attribute"       - this is the name of the attribute we are trying to check for binding
    //    "valueUpdate"     - this is the binding event that is fired, e.g. change, keyup, keypress, afterkeydown
    //    "anchorTypes"     - represents binding to an A tag
    //    "buttonTypes"     - represents binding to button, submit tags
    //    "checkedTypes"    - represents binding to checkbox and radio tags
    //    "imageTypes"      - represents binding to an IMG tag
    //    "textTypes"       - represents binding to EM, H1, H2, H3, H4, H5, H6, SPAN, STRONG tags
    //    "valueTypes"      - represents binding to password, text, textarea tags
    var conventionBindingProvider = function (options) {
        this.existingProvider = new ko.bindingProvider();

        options = options || {};

        // attribute used for our binding convention.  Default:  "data-name"
        this.attribute = options.attribute || "data-name";

        // defines which browser event KO will use to detect changes. Default: 'change'
        this.valueUpdate = options.valueUpdate || 'change';

        this.anchorTypes = options.buttonTypes || ['A'];
        this.buttonTypes = options.buttonTypes || ['button', 'submit'];
        this.checkedTypes = options.checkedTypes || ['checkbox', 'radio'];
        this.imageTypes = options.imageTypes || ['IMG'];
        this.textTypes = options.textTypes || ['EM', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'SPAN', 'STRONG'];
        this.valueTypes = options.valueTypes || ['password', 'text', 'textarea'];

        //determine if an element has any bindings
        this.nodeHasBindings = function (node) {
            if (node.getAttribute && node.getAttribute("data-bind")) {
                return this.existingProvider.nodeHasBindings(node);
            }
            return node.getAttribute ? node.getAttribute(this.attribute) || node.getAttribute("data-focus") : false;
        };

        //return the bindings given a node and the bindingContext
        this.getBindings = function getBindings(node, bindingContext) {
            var result = {};

            // If a binding is already setup, use it.
            if (node.getAttribute && node.getAttribute("data-bind")) {
                result = this.existingProvider.getBindings(node, bindingContext);
            } else {
                var item = node.getAttribute(this.attribute);
                if (item) {
                    //var desc = node.id + " (" + node.nodeName + " - " + node.type + ")";
                    var bindingAccessor = this.mapBindings(node, item, bindingContext);
                    if (bindingAccessor) {
                        var binding = typeof bindingAccessor == "function" ?
                        bindingAccessor.call(bindingContext.$data) : bindingAccessor;
                        ko.utils.extend(result, binding);
                    }
                }
            }

            // Apply focus() on the node containing the data-focus attribute.
            item = node.getAttribute("data-focus");
            if (item != null) {
                node.focus();
            }

            return result;
        };

        this.mapBindings = function (node, bindingName, bindingContext) {
            var obj = {};
            //valueUpdate: 'change'
            obj["valueUpdate"] = this.valueUpdate;

            if (this.isBinding(node.nodeName, this.anchorTypes)) {
                return function () {
                    //click: run
                    obj["click"] = bindingContext.$data[bindingName];
                    return obj;
                };
            }
            else if (this.isBinding(node.type, this.buttonTypes)) {
                return function () {
                    var bindingCanName = "can" + bindingName;
                    //click: run
                    //enable: canrun
                    obj["click"] = bindingContext.$data[bindingName];
                    if (bindingContext.$data[bindingCanName] != null) {
                        obj["enable"] = bindingContext.$data[bindingCanName];
                    }
                    return obj;
                };
            }
            else if (this.isBinding(node.type, this.checkedTypes)) {
                return function () {
                    //checked: isActive
                    obj["checked"] = bindingContext.$data[bindingName];
                    return obj;
                };
            }
            else if (this.isBinding(node.type, this.valueTypes)) {
                return function () {
                    //value: firstName
                    obj["value"] = bindingContext.$data[bindingName];
                    return obj;
                };
            }
            else if (this.isBinding(node.nodeName, this.textTypes)) {
                return function () {
                    //text: title
                    obj["text"] = bindingContext.$data[bindingName];
                    return obj;
                };
            }
            else if (this.isBinding(node.nodeName, this.imageTypes)) {
                return function () {
                    //attr: { src: imagePath };
                    obj["attr"] = {};
                    obj["attr"]["src"] = bindingContext.$data[bindingName];
                    return obj;
                };
            }

            return null;
        };

        this.isBinding = function (value, types) {
            if ($.inArray(value, types) > -1) {
                return true;
            }
            else {
                return false;
            }
        };

    };

    if (!exports) {
        ko.conventionBindingProvider = conventionBindingProvider;
    }

    return conventionBindingProvider;
}));

The first thing you might notice is that I am using Asynchronous Module Definition (AMD) with Require.js in my definition of my custom binidng provider. In the definition of my conventionBindingProvider, you will see that it has only one parameter. I am using a single options parameter that allows the user to define the options behavior for this provider.  Although the default behavior for these options should handle most of the scenarios you want, I like to have the ability to provide my own changes by just passing in an options parameter.

The attribute parameter defaults to data-name but you change this to any attribute you choose. Please note that not all attributes are the same. I wrote above that I originally tried to use the name attribute and ran into issues that not all elements have this attribute. As with Knockout’s default binding using data-bind, I chose to use data-name for my convention.

Next, you have the valueUpdate parameter that defaults to change event. You can use keyup to allow for changes to be triggered when the key is released.

The other option parameters are used for defining the elements for which this binding provider supports. You don’t need to override this but it does give you the flexibility to extend the default behavior without actually modifying the JavaScript file.

When creating a custom binding provider for Knockout, you need to implement two functions: nodeHasBindings and getBindings.

The nodeHasBindings function is used to determine if the corresponding node has the custom binding we with to use. Since we want to support the standard data-bind attribute we return existing binding provider which is the standard provider. Next, we check for the existence of the attribute we are using in the provider. We also check for a hard-coded attribute called, data-focus.

The getBindings function does the same things as the previous function, by checking to see if we want to pass the standard binding attribute to the existing provider. After this, we call a helper function mapBindings which does the heavy lifting as far as creating the binding expression. Finally, we check to see if an data-focus attribute exists. If it does, we call the focus function on the node. This is a nice convention in that it allows us to define what element we want to set focus.

Let’s take a look at the mapBindings function. This function basically creates the binding statement for Knockout. We start with applying the valueUpdate binding.

Next we start evaluating all of the nodes we are going to support with this convention. For the anchor types, we simply create a click binding.

The button types follows this same convention but also creates a binding on enable property if a function exists with a prefix of ‘can’.

The next three conditions are straight forward and simply bind against the checked, value and text.

The last binding targets the image tag. This one is a little special in that it sets the binding against the attr and then the src attribute.

With each of these condition checks we see that we are using another helper function called, isBinding. This function takes a string and one of the arrays representing the elements. This function also uses a helper jQuery function inArray to determine if the string value is contained in the array.

Finally, the provider sets the conventionBindingProvider on the Knockout object.

All you need to do is reference this JavaScript file and then add the following code to your viewmodel:

 var ViewModel = function () {
    this.firstName = ko.observable("Matthew");
    this.middleName = ko.observable("Kevin");
    this.lastName = ko.observable("Duffield");
    this.password = ko.observable("");
    this.isActive = ko.observable(false);
    this.canrun = ko.computed(function () {
        return this.isActive();
    }, this);
    this.run = function () {
        alert("You hit run!");
    };
};

var options = { attribute: "data-name", valueUpdate: 'keyup' };
//tell Knockout that we want to use an alternate binding provider
ko.bindingProvider.instance = new ko.conventionBindingProvider(options);

ko.applyBindings(new ViewModel());​

The source for this provider is located here.

Play with the sample I created on jsFiddle and change the options parameter.

Hope this helps…

Advertisements

Knockoutjs and Convention Over Configuration

September 30, 2012 1 comment

I am a big fan of getting rid of as much ceremony as possible in my development life-cycle. I also really like the paradigm for rich databinding that we were able to do in XAML technologies. Here comes Knockout.js giving us the same richness of declarative data-binding. Knockout.js is very nice but still requires a bit of scaffolding to get our markup data bound correctly.

Here is a sample of standard Knockout.js markup:

<span>First Name:</span>
<input data-bind="value: firstName" /><br />
<span>Middle Name:</span>
<input data-bind="value: middleName" type="text" /><br />
<span>Last Name:</span>
<input data-bind="value: lastName" /><br />
<span>Password:</span>
<input data-bind="value: password" type="password" /><br />
<span>Is Active:</span>
<input data-bind="checked: isActive" type="checkbox" /><br />
<button data-bind="click: run">Run</button>

The following is the same markup but now using a using a simple convention:

<span>First Name:</span>
<input data-name="firstName" /><br />
<span>Middle Name:</span>
<input data-name="middleName" /><br />
<span>Last Name:</span>
<input data-name="lastName" /><br />
<span>Password:</span>
<input data-name="password" type="password" /><br />
<span>Is Active:</span>
<input data-name="isActive" type="checkbox" /><br />
<button data-name="run">Run</button>

Now, this may not seem like a very big deal but I would say that the less markup I have to write the better. One nice thing about this approach is that it will always honor data-bind markup first and only fallback to the convention when no standard binding exists.

Here is the output for the second markup:

If you notice carefully, you will see that the button is disabled. This is because the enable property is tied to the Is Active checkbox. You can see how the button is enabled when the Is Active checkbox is checked:

Finally, here is the viewmodel that we were bound to:

var ViewModel = function () {
    var self = this;

    self.firstName = ko.observable("Matthew");
    self.middleName = ko.observable("Kevin");
    self.lastName = ko.observable("Duffield");
    self.password = ko.observable("");
    self.isActive = ko.observable(false);

    self.canrun = ko.computed(function () {
        return self.isActive();
    }, self);
    self.run = function () {
        alert("You hit run!");
    };
};

As you can see, the convention basically allows us to take the value from the data-name attribute and find the corresponding Knockout observable on the viewmodel. We also have a default convention that takes the value from the data-name attribute and finds a corresponding function with the same name. The convention also pre-pends the word “can” to the value from the data-name attribute and binds the enable property of the button to a function with that name if it exists.

In the next post, I will walk you through building this custom convention binding provider for Knockout.

Build Your Own Dashboard (BYOD) in HTML5

September 20, 2012 1 comment

I am excited to be speaking at the SQL Saturday #174 Charlotte BI Edition event on October 27, 2012!

Here is my presentation summary:

Need to have some dashboard reports that support cross-platform devices?  Ever wanted to build your dashboard and see it on the iPad or Android, or Windows 8 Surface?  With this session, we will take a look at what it takes to provide simple dashboards using goodness of HTML5.  We will look at using client-side JavaScript to provide our data using Web API and JSON.

Looking forward to seeing you there!

Windows 8 Development

September 13, 2012 Leave a comment

I wanted to follow-up on the presentations I gave during the Windows 8 DevCamp in Charlotte.  Here are the slides from the two presentations:

Cookbook I – Design Templates and Styles

Cookbook II – Data, Contracts, and Settings

Here is a link to the source code for ContosoCook:

Contoso Cookbook (HTML)

I found a sample of Contoso Labs based on the Release Preview.  If you want to use the HTML labs be sure to follow these steps required to get the code to work based on the RTM:

Contoso Labs (Release Preview)

As you are doing your development, be sure to adhere to the UX guidelines for Windows Store apps here.  You can download PDF of this here:

Windows 8 User Experience Guidelines

Live Tiles checklist

Badge Image catalog

Windows Azure Toolkit for Windows 8

Push notifications, Live Connect, and Advertising

Finally and probably the most important is the full set of code samples for developing Windows 8 applications:

Windows 8 Camp in a Box

Thanks to all who came out and are interested in doing Windows 8 development!

Hope this helps…

 

Registration of the app failed

September 10, 2012 1 comment

Recently, I have been playing with a lot of sample code on Windows 8 development and I have ran into a couple of issues while trying to get the demos or code that I have written on another computer to run.  As soon as you try to run the application, you get the following exception:

Error: DEP0700: Registration of the app failed.  An internal error occurred with error 0x80073D05.  See http://go.microsoft.com/fwlink/?LinkId=235160 for help diagnosing app deployment issues.

Here is a screen shot of the same:

If you haven’t worked a lot with Windows 8, you may not where to look as far as correcting this error.  If you take a look at the package.appxmanifest file in Visual Studio 2012 and go to the Packaging tab, you will see the following:

I discovered that if you change the certificate associated with the application, you can fix the problem.  Simply click on the “Choose Certificate…” button and you will see the following pop-up:

Next click on the “Configure Certificate…” drop-down and chose “Create Test Certificate…” and you will see the following pop-up:

Once you have done this, you should be able to run your application successfully.

Alternatives:

  • I read another post, that mentioned that if you log-out and log back in, you can then run the application without any issues.
  • I found this post on the msdn forums that mentioned if you changed the package identity, things would work.  However, according to here, your package name is unique to your Windows Store developer account and I don’t think it is a good idea to change it.

Hope this helps…