Monthly Archives: January 2015

Knockout Binding Handler: tooltip

<script type="text/javascript">
    ko.bindingHandlers.tooltip = {
        normalize: function (valueAccessor) {
            var value = ko.unwrap(valueAccessor());
            if (typeof value === "object" && "data" in value) {
                return value;
            } else {
                return { data: value };
            }
        },
        
        getOptions: function (element, valueAccessor) {
            var value = ko.bindingHandlers.tooltip.normalize(valueAccessor);
            return $.extend({}, ko.unwrap(value.options), {
                items: element,
                content: ko.unwrap(value.data)
            });
        },
        
        init: function (element, valueAccessor) {
            var options = ko.bindingHandlers.tooltip.getOptions(element, valueAccessor);
            $(element).tooltip(options);
        },
        
        update: function (element, valueAccessor) {
            var options = ko.bindingHandlers.tooltip.getOptions(element, valueAccessor);
            $(element).tooltip("option", options);
        }
    };
</script>

<div data-bind="tooltip: 'Hypertext Markup Language'">HTML</div>
<div data-bind="
    tooltip: {
        data: now().toLocaleTimeString(),
        options: { track: true }
    }">
    Time
</div>

<script type="text/javascript">
    function ViewModel() {
        var self = this;
        self.now = ko.observable(new Date());
        setInterval(function () {
            self.now(new Date());
        }, 1000);
    }
    
    ko.applyBindings(new ViewModel());
</script>

Knockout Binding Handler: sortable

<script type="text/javascript">
    ko.bindingHandlers.sortable = {
        normalize: function (valueAccessor) {
            var value = ko.unwrap(valueAccessor());
            if (typeof value === "object" && "data" in value) {
                return value;
            } else {
                return { data: valueAccessor() };
            }
        },
        
        getHandlers: function (data) {
            var startIndex;
            return {
                start: function (event, ui) {
                    startIndex = ui.item.index();
                },
                
                stop: function (event, ui) {
                    var stopIndex = ui.item.index();
                    ui.item.remove();
                    var item = data.splice(startIndex, 1)[0];
                    data.splice(stopIndex, 0, item);
                }
            };
        },
        
        init: function (element, valueAccessor) {
            var self = ko.bindingHandlers.sortable;
            var value = self.normalize(valueAccessor);
            var handlers = self.getHandlers(value.data);
            var options = $.extend({}, ko.unwrap(value.options), handlers);
            $(element).sortable(options);
            return ko.bindingHandlers.foreach.init.apply(this, arguments);
        },
        
        update: function () {
            ko.bindingHandlers.foreach.update.apply(this, arguments);
        }
    };
</script>

<ul data-bind="sortable: letters">
    <li data-bind="text: $data"></li>
</ul>

<button type="button" data-bind="click: add">Add</button>
<ul data-bind="
    sortable: {
        data: numbers,
        options: {
            handle: '.handle',
            cancel: ''
        }
    }">
    <li>
        <button type="button" class="handle">Move</button>
        <span data-bind="text: $data"></span>
    </li>
</ul>

<script type="text/javascript">
    function ViewModel() {
        var self = this;
        self.letters = ko.observableArray(["a", "b", "c"]);
        self.numbers = ko.observableArray();
        self.add = function () {
            self.numbers.push(self.numbers().length + 1);
        };
    }
    
    ko.applyBindings(new ViewModel());
</script>

Knockout Binding Handler: slide

<script type="text/javascript">
    ko.bindingHandlers.slide = {
        enabled: true,
        queue: "ko.bindingHandlers.slide",
        
        init: function (element, valueAccessor) {
            var visible = Boolean(ko.unwrap(valueAccessor()));
            $(element).toggle(visible);
        },
        
        update: function (element, valueAccessor) {
            var self = ko.bindingHandlers.slide;
            var $element = $(element);
            $element.stop(self.queue, true);
            var visible = Boolean(ko.unwrap(valueAccessor()));
            if (self.enabled) {
                var slide = visible ? "slideDown" : "slideUp";
                $element[slide]({ queue: self.queue });
                $element.dequeue(self.queue);
            } else {
                $element.toggle(visible);
            }
        }
    };
</script>

<button type="button" data-bind="click: toggle">Toggle</button>
<div data-bind="slide: visible">Hello, world!</div>

<script type="text/javascript">
    function ViewModel() {
        var self = this;
        self.visible = ko.observable(true);
        self.toggle = function () {
            self.visible(!self.visible());
        };
    }
    
    ko.applyBindings(new ViewModel());
</script>