1

I'm currently developing a layout engine using knockout as a base, but I've run into a bit of a snag. (sorry for the long post)

I'm using Knockout 3.5.1.

I have the following index.html:

<body>
    <toolbar-dock ui-name="toolbar"></toolbar-dock>
    <general-layout ui-name="main" params="resize: true">
        <!-- this one is transparent, and overlays ontop of the main screen. -->
        <general-dock ui-name="ui" params="resize: 'fit'" id="hud_overlay"></general-dock>
    </general-layout>
    <main-statusbar></main-statusbar>
</body>

general-dock has the following .html:

<horizontal-dock>
    <vertical-dock ui-name="left"></vertical-dock>
    <vertical-dock ui-name="middle">
        <horizontal-dock ui-name="top"></horizontal-dock>
            <content-dock ui-name="middle">
            </content-dock>
        <horizontal-dock ui-name="bottom"></horizontal-dock>
    </vertical-dock>
    <vertical-dock ui-name="right" ></vertical-dock>
</horizontal-dock>

The UIManager.registerDockType function registers a dock with knockout with the following parameters:

  • ComponentName: The first parameter is the name of the custom element, which is used to register with knockout.
  • DockClass: The second parameter is instantiated and passed the element.
  • TemplateString: The third parameter is the template string provided to the knockout class.

The function effectively is this:

ko.components.register(ComponentName, {
        template: TemplateString,
        viewModel: {
            createViewModel: (params, componentInfo) => {
                if (!componentInfo) {
                    throw new Error("Component didn't initialise correctly.");
                }
                var context = ko.contextFor(componentInfo.element);
                new DockClass(componentInfo.element);
                return context.$data;
            }
        }
    })

And is called like this:

UIManager.registerDockType("vertical-dock", VerticalDock, "<!-- ko template: { nodes: $componentTemplateNodes } --><!-- /ko -->");
UIManager.registerDockType("horizontal-dock", HorizontalDock, "<!-- ko template: { nodes: $componentTemplateNodes } --><!-- /ko -->");
UIManager.registerDockType("content-dock", CenterDock, "<!-- ko template: { nodes: $componentTemplateNodes } --><!-- /ko -->");

I expected the following HTML to be output:

<body>
    <toolbar-dock ui-name="toolbar"></toolbar-dock>
    <general-layout ui-name="main" params="resize: true">
        <horizontal-dock>
            <vertical-dock ui-name="left"></vertical-dock>
            <vertical-dock ui-name="middle">
                <horizontal-dock ui-name="top"></horizontal-dock>
                    <content-dock ui-name="middle">
                        <!-- There should be an error, blank entry or infinite duplication at this point because $componentTemplateNodes is now exhausted? -->
                    </content-dock>
                <horizontal-dock ui-name="bottom"></horizontal-dock>
            </vertical-dock>
            <vertical-dock ui-name="right" ></vertical-dock>
        </horizontal-dock>
    </general-layout>
    <main-statusbar></main-statusbar>
</body>

But what I'm getting is this:

<body>
    <toolbar-dock ui-name="toolbar"></toolbar-dock>
    <general-layout ui-name="main" params="resize: true">
        <horizontal-dock>
            <!-- ko template: { nodes: $componentTemplateNodes } -->
                <!-- this one is transparent, and overlays ontop of the main screen. -->
                <general-dock ui-name="ui" params="resize: 'fit'" id="hud_overlay"></general-dock>
            <!-- /ko -->
        </horizontal-dock>
    </general-layout>
    <main-statusbar></main-statusbar>
</body>

Why does this happen? Why is it that within the horizontal-dock I'm getting the $componentTemplateNodes of the general-layout?

When I was using knockout 3.4.0 and highlighting the <!-- ko template node using knockout-inspector it was showing the $componentTemplateNodes that I was expecting, however the DOM actually had the parent's $componentTemplateNodes. After upgrading to 3.5.0 knockout-inspector and the DOM are showing the same thing (although not what I expected).


What I expected is that (like with $data) a new $componentTemplateNodes is created every time a knockout controlled template node is entered if that template node has children. And that when recursing down the dom each child that fulfilled that criteria would replace the current $componentTemplateNodes with it's own $componentTemplateNodes.

This would mean that the $componentTemplateNodes for general-dock would be:

        <!-- this one is transparent, and overlays ontop of the main screen. -->
        <general-dock ui-name="ui" params="resize: 'fit'" id="hud_overlay"></general-dock>

But once we get to the horizontal-dock when knockout is expanding the general-dock it would create a new $componentTemplateNodes value (because it has children) containing the following representation:

    <vertical-dock ui-name="left"></vertical-dock>
    <vertical-dock ui-name="middle">
        <horizontal-dock ui-name="top"></horizontal-dock>
            <content-dock ui-name="middle">
            </content-dock>
        <horizontal-dock ui-name="bottom"></horizontal-dock>
    </vertical-dock>
    <vertical-dock ui-name="right" ></vertical-dock>

I expected that the only way to get back to the original $componentTemplateNodes would be to either recurse up $parentContext or pass them down as a parameter.

Is this a bug or am I doing something stupid?

Griffork
  • 683
  • 1
  • 5
  • 21

0 Answers0