akuz
akuz

Reputation: 637

Knockout.js composable components?

I am thinking of using Knockout.js to create reusable components. However, by reading the docs, I don't know how would I implement a component that can hold other (potentially different with each use) components inside it.

For example, I would like to implement a side-menu-view component, which would contain a title bar with menu button, a menu panel, and a content panel. The contents of the menu and content panels should not be defined in advance. For example, in one use case I would put a list-view component into the menu panel, in another use case I could put a list of checkboxes into the menu panel.

As what I understand from the docs, in Knockout.js the template of a component must be defined fully, and does not offer places where other components could be inserted later. Or am I wrong? Can it be done? Thanks!

UPDATE:

I want to create a component , which could be used as:

<side-menu-view>
  <menu>
    <!-- I can put anything here -->
  </menu>
  <content>
    <!-- I can put anything here -->
  </content>
</side-menu-view>

I understand the child nodes of a component can be accessed via $componentTemplateNodes, but then I want to be able to get the contents of <menu> and <content> separately, and put it within the appropriate places of my component layout.

UPDATE 2:

Example use:

<side-menu-view>
  <menu>
    This is a menu!
  </menu>
  <content>
    This is content!
  </content>
</side-menu-view>

Or like this:

<side-menu-view>
  <menu>
    <ul>
      <li><a href="#">1</a></li>
      <li><a href="#">2</a></li>
      <li><a href="#">3</a></li>
    </ul>
  </menu>
  <content>
    <h1>Title</h1>
    <p>Some text</p>
  </content>
</side-menu-view>

Upvotes: 0

Views: 227

Answers (2)

Milimetric
Milimetric

Reputation: 13549

If you're using the custom html element syntax, then you're right, you have to know the components when you write your html, like so:

<menu-panel>
    <list params="..."/>
</menu-panel>

However, you have the component binding which lets you choose the component at run time:

<menu-panel>
    <div data-bind="component: {
        name: yourDynamicComponentName,
        params: { ... },
    }"/>
</menu-panel>

Note, of course, that yourDynamicComponentName must still be registered so knockout knows where to find it.

RE: Update 2 (focusing only on the menu control as it's obviously similar for the content control):

So you just define two components, one called menu-list and one called menu-static:

// html for a component called "menu-list"
<ul>
  <li><a href="#">1</a></li>
  <li><a href="#">2</a></li>
  <li><a href="#">3</a></li>
</ul>

// html for a component called "menu-static"
This is a menu!

And in your viewModel for side-menu-view you can have a property called menuType, and you would use it in the html for side-menu-view like this:

// html for "side-menu-view"
<div data-bind="component: { name: menuType }"/>

So now you can set menuType('menu-static') or menuType('menu-list') when you want to toggle between menu types.

Upvotes: 1

Jack
Jack

Reputation: 1769

A knockout's model can be "pre-defined" for common usage and then extended for particular purpose. This means:

  1. create an object/model as you'd do normally
  2. create an object/model which has the extended properties
  3. mix the two models with, i.e., jQuery's $.extend

Example:

var mainModel = function () {
    this.blablabla = ko.observable('blablabla');
}

var extendedModel = function () {
    this.sup = ko.observable('sup');
}

var myModelInstance = $.extend({}, new mainModel(), new extendedModel());

console.log(myModelInstance.blablabla(), myModelInstance.sup()); // "blablabla", "sup"

Upvotes: 0

Related Questions