Skip to content

Namespaced bindings - #74

Closed
hunterloftis wants to merge 4 commits into
knockout:masterfrom
hunterloftis:master
Closed

hunterloftis wants to merge 4 commits into
knockout:masterfrom
hunterloftis:master

Conversation

@hunterloftis

Copy link
Copy Markdown

After using KO extensively in our latest web app (clickdummy.com) we loved it - it's brilliant! ...but we had some real beef with its complexity limits in these scenarios:

  • undefined VMs (single-page app, some data upfront, the rest ajaxed in)
  • loose coupling (applyBindings(vm, domElement) means you have to explicitly bind/tightly couple)
  • dynamic binding
  • forced bad architecture (global variables, monolithic VM objects)

The clear solution to this is namespaced binding:

  • bind after VM is defined, only for that VM
  • no more need to scope to a particular DOM container / can loosely couple
  • can bind dynamically
  • good architecture (related VMs in closure, bind from closure, no data leakage, good modularity)

So here it is.

There's a complex demo with namespaces (designed for the latest browsers):
https://developer.mozilla.org/en-US/demos/detail/ghostwriter-art-studio/launch

It's backwards-compatible, so it won't break any existing KO implementations. New implementations can deprecate DOM-containers for namespaces (or stick with the old ways if they prefer).

Example:

span data-bind="text: userName"
a data-bind="click: newImage"
a data-bind-eraser="click: activate"
div data-bind-marker="visible: visible"

ko.applyBindings(GlobalViewModel);
ko.applyBindings(marker, 'marker');
ko.applyBindings(eraser, 'eraser');

cheers,
Hunter Loftis (hunterloftis) via Skookum (skookum)
Chris Gomez (evlapix)

@thelinuxlich

Copy link
Copy Markdown

+1 for this

@SteveSanderson

Copy link
Copy Markdown
Contributor

This looks like a really nice alternative way of structuring a set of view models. How would you feel about making this into a Knockout plugin?

The reason I ask is that one of the reasons why jQuery has been so stable and successful is that the core has been kept extremely tight and they've been diligent about implementing all additional functionality as plugins wherever possible. This allows their project to scale up significantly - the small core team could never manage to maintain, support, and document the entire jQuery ecosystem, and they don't need to, because most of the ecosystem is plugins.

To keep Knockout as tight and maintainable as it is now, and for the project to scale up without me becoming a bottleneck, I'd like to make sure people can implement their extensions as plugins in the same way. I'd be very happy to host a "ko.namespaces" plugin on knockoutjs.com (like the ko.mapping plugin that's already there) and let you keep ownership of it. If KO needs to expose some extra hooks so you can integrate your code cleanly, I'm happy to add those hooks.

What do you think?

@hunterloftis

Copy link
Copy Markdown
Author

Sold! I'll start on a plugin version.

@hunterloftis

Copy link
Copy Markdown
Author

For namespaced bindings, I had implemented them to keep backwards-compatibility with existing applyBindings:

ko.applyBindings(pen, 'pen');
ko.applyBindings(otherVM); // works fine together

I like this style because it's less to remember (and also jQuery-like in that you can pass several different argument combinations to a minimal set of methods).

As a plugin, I could override applyBindings or do something more like:

ko.ns.applyBindings(pen, 'pen');
ko.applyBindings(otherVM);

This is more 'plugin-like,' but I prefer the simpler first version. What do you think?

@ifandelse

Copy link
Copy Markdown

@hunterloftis - my personal take is that I like the first approach better simply because it keeps the API intact & consistent. </$.02>

@hunterloftis

Copy link
Copy Markdown
Author

Ditto. Implemented version #1 as a plugin. The implementation is so small and simple I wouldn't mind merging with core, but I do understand why S.S. feels overwhelmed with maintenance. Also working on some other KO plugins.

@gilesbradshaw

Copy link
Copy Markdown
Contributor

I've come up with a different idea of how to do this which is to allow knockout to create multiple instances of itself which you can then configure to have different namespaces and also in other ways (eg applying different plugins to different instances) However it isn't a plugin but just organises the code a little differently by adding a factory method to the ko object so it can clone itself. some stuff has to be shared between instances (observable and dependent observable) In fact I suspect a lot more of the code should be.

What I want this for is so I can display arbitrary data sent from the server on the basis of meta data.

here's an example spec with namespaced data-bind (you can call it whatever you like) and also containerless binding tag. Each knockout is independently maintaining its bindingcontext.

'containerless binding with two models': function() {
    model = { hello: { goodbye: "seeyou" } };
    model1 = { hello: { goodbye: "nextwednesday" } };
    testNode.innerHTML = 
    "<!-- ko with: hello -->
         <span data-bind='text : goodbye'></span>
         <!-- kons with: hello -->
             <span     data-bind-ns='text : goodbye'></span>
         <!-- /kons -->
     <!-- /ko -->";
    ko.applyBindings(model, testNode);
    var myKo = ko.factory();
    myKo.bindingConfig.defaultBindingAttributeName = 'data-bind-ns';
    myKo.bindingConfig.virtualElementName = "kons";
    myKo.applyBindings(model1, testNode);

    value_of(testNode.childNodes[1].textContent || testNode.childNodes[1].innerText).should_be("seeyou");
    value_of(testNode.childNodes[3].textContent || testNode.childNodes[3].innerText).should_be("nextwednesday");
},

@hades200082

Copy link
Copy Markdown

How does this work with HTML comment bindings?

@crissdev

Copy link
Copy Markdown

@hunterloftis I wish I had this idea a while ago.
@hades200082 I really like your question. 👍
@SteveSanderson Wouldn't it be better if KO would have a plugin repository so we don't have to wander all over the internet to find them?

@hades200082

Copy link
Copy Markdown

Also.. I couldn't get this to work with the latest version of Knockout ... just didn't seem to work at all.

@brunohstein

Copy link
Copy Markdown

Is there a way to namespace bindings like this in the current version?

We have a large application with several components that auto-initialize. The components are rendered on the server side and we don't know the context in which they will be used. A component can be rendered in a page that don't even use Knockout at all. We are looking for a simple tool to bind data and event handlers to the view and Knockout still looks like a solid tool for that, but as we can have components inside other components, we have problems regarding the context of the binding instructions.

If we could namespace the data-bind (e.g. data-image-field-bind) we would be able to keep the components completely decoupled from each other. I'm not familiar with the Knockout code. Is there a way to write a plugin to the current version to achieve that? Maybe with some directions I would be able to do it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants