I think you were close to your second decision. What you can do is create a custom binding that simply stops the site bindings, like the example presented on this page http://knockoutjs.com/documentation/custom-bindings-controlling-descendant-bindings.html
But, as you say, if they use knockout on the site already, you need this binding to be on this version of the knockout, so you should wrap it in if (ko), like this ...
if(ko){ ko.bindingHandlers.allowBindings = { init: function(elem, valueAccessor) { // Let bindings proceed as normal *only if* my value is false var shouldAllowBindings = ko.unwrap(valueAccessor()); return { controlsDescendantBindings: !shouldAllowBindings }; } }; }
Then, since you are using requirejs, you can map your knockout version to something other than ko, like ko2 or something else.
define(["knockout", "jquery"], function (ko2, $) { var myViewModel = { SomeComponentLevelBinding: ko2.observable() }; ko2.applyBindings(myViewModel, document.getElementById('someElementId')); }
Then your html might look something like this ...
<body> <div> <span data-bind="text: SomeSiteLevelBinding"></span> </div> <div data-bind="allowBindings: false"> <div id="someElementId"> <span data-bind="text:SomeComponentLevelBinding"></span> </div> </div> </body>
Since the site is already using knockout, and we have added allowBindings to this instance, we stop the knockout version of the site to control anything inside this div. Then, because we only apply the bindings to the div inside it from our component, using the component version of the knockout, we must have 2 versions of the knockout on the same page as the slide together.
This should also be good if they do not have a knockout on the page, because if they are not used, we do not add allowBindings, and since we apply bindings to the div inside it, the allowBindings:false data binding attribute is allowBindings:false in this script.