KO Binding events to a component parentElement

by Kevin Van Lierde

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<h3>Test for <code data-bind="text: test"></code></h3><br><br>
<custom-button params="msg: myMsg, label: label"></custom-button>
<br><br><br>
<input type="text" data-bind="value: myMsg">
<template id="custom-button-tmpl">
    <button type="button" data-bind="text: label"></button>
</template>

CSS

custom-button, .custom-button {
  border: 1px solid black;
  padding: 1rem;
  cursor: pointer;
}
h3 {font-weight: normal }

JavaScript

var options = ['createViewModel','Custom templateLoad','ko.bindingProvider.instance.preprocessNode'],
    test = 2,
    customButtonComponent = { // test component
        viewModel: customButton,
        template: { element: 'custom-button-tmpl'}}; 

function customButton(params) {
    var self = this;
    this.msg = params.msg;
    this.label = params.label;
    this.someProp = true;
}
switch (options[test]) {
    case 'createViewModel': 
        customButtonComponent.viewModel = { createViewModel: function(params, componentInfo) {
            var element = componentInfo.element, 
                // access to viewModel the component is rendered in
                data = ko.dataFor(element), 
                // access to the $context variable, in this case === $root and $data
                context = ko.contextFor(element),
                // access to component params and name
                compInfo = ko.bindingProvider.instance.getBindings(element, context);
            $(element).on('click', function() { confirm(params.msg())});
            return new customButton(params);
        }};
    break;
    case 'Custom templateLoad':
        customButtonComponent.template.beforeRender = function(html) {
            var container = $('<div></div>'), 
                btn = $(html);
            btn.attr('data-bind', btn.attr('data-bind') + ', click: function() { confirm(msg()) },');
            container.append(btn).append('<code data-bind="text: someProp"></code>');
            return container.html();
        };
        var templateLoader = { loadTemplate: function(name, templateConfig, callback) {
            if (templateConfig.beforeRender) {
                var template = typeof templateConfig === 'string' ? templateConfig : 
                    (templateConfig.element ? document.getElementById(templateConfig.element).innerHTML : templateConfig);
                template = templateConfig.beforeRender(template);
               ...