Error flags

by whelkaholism

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.2/moment.min.js"></script>
<button data-bind="click: set1">Name failed</button>
<button data-bind="click: set2">Email failed</button>
<button data-bind="click: clear">Clear</button>
<hr/>
<!-- ko with: Module -->
<!-- ko with: Model -->
With options in child context: <div class="efs" data-bind="ef: { flags: ['ef__namerequired'], field: $parents[1].ErrorFlags }"></div>
<!-- /ko -->
<!-- /ko -->
<hr/>
Default: 
<div class="efs" data-bind="___XXX___ef: ['ef__emailrequired', 'ef__emailinvalid']"></div>
<hr/>
<div data-bind="text: CurrentErrorFlags"></div>

JavaScript

ko.bindingHandlers.ef = {
	init:
    	function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
    	{
			// Get current value of supplied value
			var val = ko.unwrap(f_valueaccessor());
            var field = bindingcontext.$data.ErrorFlags;
			
			if(!!val.flags)
			{
                field = val.field || field;
				val = val.flags;
			}
            
            if(field && val)
            {
                field.subscribe(
                    function()
                    {                 
						var visibleflags = [];
						
						for(var i = 0; i < val.length; i++)
						{
							var err = ko.utils.arrayFirst(ko.unwrap(field), function(x) { return x.Flag == val[i]; });
							
							if(err)
								visibleflags.push(err);                        
						}                
					 
						$('<div class="ef" data-bind="text: Message"></div>').appendTo(el);
						ko.applyBindingsToNode(el, { foreach: visibleflags });
                    });
            }
            
            return { controlsDescendantBindings: true };
        }
};


function Model(data, mapping)
{
    var _this = this;
    var _mapping = $.extend({}, {}, mapping);
    
    this.ErrorFlags = ko.observableArray();
    
    this.Module = ko.observable({ Model: ko.observable({}) });
    
    this.CurrentErrorFlags = ko.computed(
		function()
    	{
           	var a = [];
        	
            $.each(_this.ErrorFlags(), function() { a.push(this.Flag); });
            
			return a.length > 0 ? a.join(', ') : '(empty)';
    	}        
    );
    
    if(data)
        ko.mapping.fromJS(data, _mapping, _this);
    
    this.set1 = function() 
    { 
        this.ErrorFlags([
            { Flag: 'ef__namerequired', Message: 'Name is required' }
        ]); 
    };
    
    this.set2 = function()
    { 
        this.ErrorFlags([
            { Flag: 'ef__emailrequired', Message: 'Email is required'},
            { Flag: 'ef__emailinvalid', Message: 'This email is invalid' }
        ]);
   ...