KO Flags Binding

by whelkaholism

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.js"></script>
<label><input type="checkbox" value="IH" data-bind="flags: Flags"/>IH</label>
<br/>
<label><input type="checkbox" value="OV" data-bind="flags: Flags"/>OV</label>

<div data-bind="text:Flags">
</div>

JavaScript

ko.bindingHandlers.flags = {
    init: function(el, f_valueaccessor, allbindings)
    {
        var f_flagval = ko.pureComputed(function()
        {
            return allbindings.has('flagsValue') ? ko.unwrap(allbindings.get('flagsValue')) : el.value;
        });

        // Update model FROM view (i.e. `write` binding)
        var f_updatemodel = function()
        {
            if (ko.computedContext.isInitial())
                return;

            var elval = f_flagval();
            var curr = ko.unwrap(f_valueaccessor())
            var a = [];

            if (!curr )
                el.checked && a.push(elval);
            else
            {
                var acurr = curr.split(/\s*,\s*/);
                
                for (var i = 0; i < acurr.length; i++)
                    if (acurr[i] != elval)
                        a.push(acurr[i]);

                el.checked && a.push(elval);
            }
            
            f_valueaccessor()(a.join(', '));
        };

        // Update view FROM model (i.e. `read` binding)
        var f_updateview = function()
        {
            var elval = f_flagval();
            var curr = ko.unwrap(f_valueaccessor())
           
            el.checked = curr && ko.utils.arrayIndexOf(curr.split(/\s*,\s*/), elval) >= 0;
        };
      
        // Set up two computeds to update the binding:
        // The first responds to changes in the checkedValue value and to element clicks
        ko.computed(f_updatemodel, null, { disposeWhenNodeIsRemoved: el });
        ko.utils.registerEventHandler(el, 'click', f_updatemodel);

        // The second responds to changes in the model value (the one associated with the flags binding)
        ko.computed(f_updateview, null, { disposeWhenNodeIsRemoved: el });
    }
};

ko.bindingHandlers.flagsValue = {
    update: function(el, f_valueaccessor)
    {
        el.value = ko.unwrap(f_valueaccessor());
    }
};

var ViewModel = function()
{
	this.Flags =...