This is a question to clarify the best method (or any method!) for achieving this. It may be the way I'm trying to apply my .net coding experience to this new way of doing things but I cannot believe this is not a real world problem for many coders.
So. Master view/viewmodel uses many sub views on the page as certain sections change depending on user choices/actions. These sub views are composed into the master page:
<div data-bind="compose: { model: articleSection, preserveContext: true }"></div>
...and within the sub view I am able to refer to root observables that control the master view like so:
<a href="#" class="btn" data-bind="css: { 'btn btn-default': true, 'btn-primary': $root.inEditMode() }, click: $root.setEditMode, enable: $root.articleSelected()">Edit</a>
However, one of the sub views itself has a sub sub view which uses a custom binding and a template for construction as it's a treeview and needs to be able to recursively construct the layout.
The sub view code is just:
<div id="fancytree" data-bind="groupTree: treeGroups">
<!--<ul data-bind="template: { name: 'itemTmpl', foreach: treeGroups }, groupTree: {}"></ul>/-->
</div>
The template is just:
<script id="itemTmpl" type="text/html">
<!-- Template used in labtool for tree-->
<li>
<span>
<span data-bind="text: name" />
</span>
<ul data-bind="template: { name: 'itemTmpl', foreach: children }"></ul>
</li>
</script>
The custom binding is:
ko.bindingHandlers.groupTree = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
var tm = valueAccessor();
var tmUnwrapped = tm();
$(element).fancytree({
minExpandLevel: 1,
source: tmUnwrapped,
lazyload: function (e, data) {
data.result = datacontext.getGroupChildren('1111');
},
activate: function (event, data) {
var node = data.node;
var tg = rootVm.selectedGroupId();
alert(node.title);
},
})
}
So my problem is that I cannot get at what I think of as a "global variable" from my .net days which is an observable in my top-level root viewmodel called "selectedArticle". When a user clicks on the tree view node, the "activate" function is fired, the alert pops up with the correct details and I simply want to be able to put that value into the observable in my root viewmodel which is, effectively, two levels up from the binding context of the custom binding handler.
This HAS to be something that other people do, surely? I've googled until I'm blue in the face but I'm obviously missing the keywords or concepts I need to get the hits I need. In pseudo-code in the custom binding "activate" function I simply want to be able to type in something like "root.selectedArticle = node.title" but obviously root is not available in that manner, so that's where I come unstuck!
bindingContext.$root
should be your root viewmodel... – nemesvpreserveContext: true
in all yourcompose
binding until the top? – nemesv<!--<ul data-bind="template: { name: 'itemTmpl', foreach: treeGroups }, groupTree: {}"></ul>/-->
and there's no way to do a compose binding on that! – TheMook