Archive

Archive for September, 2012

Creating a custom Knockout binding for the jQuery Mobile ListView

September 22, 2012 3 comments

Introduction

A shift towards more client side web development is happening in the IT industry. This allows developers to build quicker responding and more user friendly GUIs for their end users. This shift is made possible with the arrival of HTML5 and more powerful JavaScript frameworks. Features like camera access, local storage, drag & drop … previously only available in native applications are now also possible in web applications.

In the past I have already written about jQuery Mobile. It is an excellent JavaScript framework to develop mobile web applications or hybrid applications. Another useful framework for the development of modern web applications is Knockout. This framework makes the MVVM design pattern possible in web applications. MVVM stands for Model-View-ViewModel. It is a software pattern of Microsoft commonly used in WPF and Silverlight applications.

In this article I will explain how to build a custom Knockout binding for the jQuery Mobile ListView.

Context

Why do we need a custom binding for the jQuery Mobile ListView? With what is provided out of the box, it is already possible to bind to a ListView. Unfortunately, we are then rather limited in functionality. Imagine the following example: I have a JavaScript array of food. The food can be divided in a number of categories (fruit, vegetables and snacks). I want to show the food in a jQuery Mobile ListView and show a divider per category.

foodapp

With the foreach binding that is provided out of the box in Knockout, I would have to divide my food in 3 arrays. If not, it would not be possible to add a divider per category.

function FoodViewModel(name, category, image) {
    var self = this;

    self.name = name;
    self.category = category;
    self.image = image;
};

function MainViewModel() {
    var self = this;

    self.fruit = ko.observableArray([
        new FoodViewModel("Apple", "Fruit", "/Images/apple.jpg"),
        new FoodViewModel("Banana", "Fruit", "/Images/banana.jpg"),
        new FoodViewModel("Pear", "Fruit", "/Images/pear.jpg")
    ]);

    self.vegetables = ko.observableArray([
        new FoodViewModel("Carrot", "Vegetables", "/Images/carrot.jpg"),
        new FoodViewModel("Tomato", "Vegetables", "/Images/tomato.jpg"),
    ]);

    self.snacks = ko.observableArray([
        new FoodViewModel("Cookie", "Snacks", "/Images/cookie.jpg")
    ]);
};
<ul data-role="listview" data-divider-theme="b">
    <li data-role="list-divider">Vegetables</li>
    <!-- ko foreach: vegetables -->
    <li>
        <a href="#">
            <img data-bind="attr: { src: image }" />
            <h3 data-bind="text: name"></h3>
        </a>
    </li>
    <!-- /ko -->

    <li data-role="list-divider">Fruit</li>
    <!-- ko foreach: fruit -->
    <li>
        <a href="#">
            <img data-bind="attr: { src: image }" />
            <h3 data-bind="text: name"></h3>
        </a>
    </li>
    <!-- /ko -->

    <li data-role="list-divider">Snacks</li>
    <!-- ko foreach: snacks -->
    <li>
        <a href="#">
            <img data-bind="attr: { src: image }" />
            <h3 data-bind="text: name"></h3>
        </a>
    </li>
    <!-- /ko -->
</ul>

I found this quite limiting, because I preferred to have one list containing all my food.

The jqmListView custom binding

In order to resolve this issue, I decided to develop a custom binding for the jQuery Mobile ListView. I based myself on the source of the foreach binding and customized it to have support for the features of the ListView.

It can be applied in two ways:

  1. <ul data-role=”listview” data-divider-theme=”b” data-bind=”jqmListView: food”>
  2. <ul data-role=”listview” data-divider-theme=”b” data-bind=”jqmListView: { data: food, divider: generateDivider, dividerCompareFunction: sortFood, itemCompareFunction: sortItems }”>

The properties “divider”, “dividerCompareFunction” and “itemCompareFunction” are optional.

divider

The property “divider” allows to customize the generation of the dividers for the ListView. It can be assigned a function that will called for every item in the list bound to the ListView. The function must return the category name for each item.

An example:

self.generateDivider = function (data) {
	return data.category;
};

dividerCompareFunction

The property “dividerCompareFunction” allows to customize the sorting of the dividers. By default they are sorted alphabetically.

An example:

self.sortFood = function (divider1, divider2) {
	var weights = new Object;
	weights["Vegetables"] = 1;
	weights["Fruit"] = 2;
	weights["Snacks"] = 3;

	return weights[divider1] - weights[divider2];
};

itemCompareFunction

The property “itemCompareFunction” allows to customize the sorting of the items of a given category. By default they are not sorted in order of appearance in the JavaScript list.

An example:

self.sortItems = function (item1, item2) {
	return item1.name.localeCompare(item2.name);
}

Sample Code

If we use the jqmListView binding, we can rewrite our sample application:

function FoodViewModel(name, category, image) {
    var self = this;

    self.name = name;
    self.category = category;
    self.image = image;
};

function MainViewModel() {
    var self = this;

    self.food = ko.observableArray([
        new FoodViewModel("Carrot", "Vegetables", "/Images/carrot.jpg"),
        new FoodViewModel("Apple", "Fruit", "/Images/apple.jpg"),
        new FoodViewModel("Pear", "Fruit", "/Images/pear.jpg"),
        new FoodViewModel("Tomato", "Vegetables", "/Images/tomato.jpg"),
        new FoodViewModel("Banana", "Fruit", "/Images/banana.jpg"),
        new FoodViewModel("Cookie", "Snacks", "/Images/cookie.jpg")
    ]);

    self.generateDivider = function (data) {
        return data.category;
    };

    self.sortFood = function (divider1, divider2) {
        var weights = new Object;
        weights["Vegetables"] = 1;
        weights["Fruit"] = 2;
        weights["Snacks"] = 3;

        return weights[divider1] - weights[divider2];
    };

    self.sortItems = function (item1, item2) {
        return item1.name.localeCompare(item2.name);
    }
};
<ul data-role="listview" data-divider-theme="b" data-bind="jqmListView: { data: food, divider: generateDivider, dividerCompareFunction: sortFood, itemCompareFunction: sortItems }">
    <li>
        <a href="#">
            <img data-bind="attr: { src: image }" />
            <h3 data-bind="text: name"></h3>
        </a>
    </li>
</ul>

The food sample application is a very simple application were the differences between the foreach and the jqmListView bindings are minor. But the jqmListView is a lot more flexible then the foreach binding in more complex cases. For example: if the data is coming from the server using a REST call and we don’t know beforehand all the available categories that will send to the browser.

You can download the sample from: http://sdrv.ms/Ol0LRY

jqmListView Code

Below you can find the source code  of my jqmListView binding. I will also upload this to GitHub.

(function () {
    ko.bindingHandlers.jqmListView = {
        init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            // Support anonymous templates
            var bindingValue = ko.utils.unwrapObservable(convertToBindingValue(valueAccessor));

            if ((element.nodeType == 1 || element.nodeType == 8)) {
                // It's an anonymous template - store the element contents, then clear the element
                var templateNodes = element.nodeType == 1 ? element.childNodes : ko.virtualElements.childNodes(element),
                    container = ko.utils.moveCleanedNodesToContainerElement(templateNodes); // This also removes the nodes from their current parent
                new ko.templateSources.anonymousTemplate(element)['nodes'](container);
            }
            return { 'controlsDescendantBindings': true };
        },
        update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
            var bindingValue = ko.utils.unwrapObservable(convertToBindingValue(valueAccessor));

            // Clean the current children
            $(element).empty();

            var dataArray = (bindingValue['data']) || [];
            var dividerFor = bindingValue['divider'];

            var dividerDictionary = new Object();
            for (var i = 0; i < dataArray.length; i++) {
                var dividierName = dividerFor(dataArray[i]);

                dividerDictionary[dividierName] = (dividerDictionary[dividierName]) || [];
                dividerDictionary[dividierName].push(dataArray[i]);
            }

            $.each(sortKeys(dividerDictionary, bindingValue.dividerCompareFunction), function (index, key) {
                if (key !== "") {
                    $(element).append('<li data-role="list-divider">' + key + '</li>');
                }

                var tempElement = document.createElement("div"); // Create temp DOM element to render templating
                ko.renderTemplateForEach(element, dividerDictionary[key].sort(bindingValue.itemCompareFunction), /* options: */bindingValue, tempElement, bindingContext);
                $(element).append($(tempElement).children()); // Add data to listview
            });

            $(element).listview('refresh');
        }
    };

    function convertToBindingValue(valueAccessor) {
        /// <summary>Standardizes the properties of the of the valueAccessor object.</summary>
        /// <returns>An object containing standardized binding properties.</returns>

        var bindingValue = ko.utils.unwrapObservable(valueAccessor());

        // If bindingValue is the array, just pass it on its own
        if ((!bindingValue) || typeof bindingValue.length == 'number')
            return {
                'data': bindingValue,
                'divider': function () { return ""; },
                'templateEngine': ko.nativeTemplateEngine.instance
            };

        // If bindingValue.data is the array, preserve all relevant options
        return {
            'data': ko.utils.unwrapObservable(bindingValue['data']),
            'divider': bindingValue['divider'] || function () { return ''; },
            'dividerCompareFunction': bindingValue['dividerCompareFunction'],
            'itemCompareFunction': bindingValue['itemCompareFunction'],
            'includeDestroyed': bindingValue['includeDestroyed'],
            'afterAdd': bindingValue['afterAdd'],
            'beforeRemove': bindingValue['beforeRemove'],
            'afterRender': bindingValue['afterRender'],
            'templateEngine': ko.nativeTemplateEngine.instance
        };
    };

    function sortKeys(data, compareFunction) {
        /// <summary>Convert the properties of a given object to an array and return them in sorted order.</summary>
        /// <param name="data">The object who's properties must be sorted.</param>
        /// <param name="compareFunction">The compare function that must be used during sorting.</param>
        /// <returns type="Array">The sorted properties of the object.</returns>

        var keys = Array();

        for (var key in data) {
            keys.push(key);
        }

        return keys.sort(compareFunction);
    }
})();
Categories: jQuery, MVVM

Logging all unhandled exceptions in WCF with Log4Net

September 5, 2012 2 comments

Scientific studies have shown that all applications contain a number of bugs. It is naïve to think that your applications would be bug free. When bugs occur is important that the necessary information gets logged to reproduce and fix the issues.

Assuring that all unhandled exceptions get logged in crucial. If you don’t now all the unhandled exceptions you will be blind for what happens in the production environment impacting your end-users. WCF produces the necessary hook to now when an unhandled exception has occurred in your services: the IErrorHandler. In this short article, I will demonstrate a simple implementation that logs these exceptions with Log4Net.

The most important component in this example is ofcourse the error handler implementation itself. The method “HandleError” gets called for every unhandled exception by the WCF stack. This method has to indicate with its return value if it has “handled” the exception or if it remains “unhandled”. In our implementation we just log it with Log4Net and indicate to WCF that it remains unhandled and has to pass the stack further.

public class Log4NetErrorHandler : IErrorHandler
{
    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    public bool HandleError(Exception error)
    {
        log.Error("An unexpected has occurred.", error);

        return false; // Exception has to pass the stack further
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
    }
}

The only thing that remains now is to hook this IErrorHandler implementation into the WCF stack. To do this, we must implement a new service behavior. Below you can find the necessary code.

public class Log4NetServiceBehavior : IServiceBehavior
{
    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        IErrorHandler errorHandler = new Log4NetErrorHandler();

        foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
        {
            channelDispatcher.ErrorHandlers.Add(errorHandler);
        }
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

Next we must implement a Behavior Extension Element to this into WCF stack using the web.config or the app.config

public class Log4NetBehaviorExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof (Log4NetServiceBehavior); }
    }

    protected override object CreateBehavior()
    {
        return new Log4NetServiceBehavior();
    }
}

Now we can declare in the config that WCF must use our custom service behavior extension.

<system.serviceModel>
<services>
<!-- We define our WCF Services ... -->
</service>
</services>

<behaviors>
<serviceBehaviors>
<behavior>
<log4net />
</behavior>
</serviceBehaviors>
</behaviors>

<extensions>
<behaviorExtensions>
<add name="log4net"
type="MyProject.Log4NetBehaviorExtensionElement, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
</system.serviceModel>
Categories: C#, WCF