Knockout, Binding handlers and RequireJS/AMD

304 views
Skip to first unread message

Gunnar Liljas

unread,
Jul 2, 2014, 8:40:28 PM7/2/14
to knock...@googlegroups.com
Hi!

Our project is growing, so I've started to test ways to make it more structured and modularized. I've started to create viewmodels as RequireJS modules, which is nice for injecting dependencies or loading viewmodels dynamically, e.g based on routing conventions.

However, things have been less than smooth, and I found myself googling "hate RequireJS" in pure frustration.

The thing is, Knockout itself, and quite a few binding handlers, uses a UMD technique to decide if it should be loaded into the global "ko" namespace or defined as an AMD module. But that makes it a distinct either or scenario. If Knockout is defined as an AMD module, all my old code breaks, since "ko" no longer exists, and if I load Knockout in the old way, all extensions which are loaded as AMD modules break, since the "knockout" dependency is nowhere to be found. I guess they could be smarter, and check if window.ko exists and appears to be Knockout.

Currently my solution is to load Knockout and all extensions before "require.js", so that everything is loaded "old school"

Firstly, I'm guessing there are better ways, e.g using shims, so I'd really appreciate some guidance and experiences.

Secondly, I'm not completely sold on the concept. Sure, putting things in the global scope is bad for your programmer karma, but "ko" is not just some instance floating around. It's the starting point for the entire extensibility API. All the tutorials and examples (even for new 3.2 functionality) assume you're doing things in the nice "old" way...

ko.bindingHandlers.someThing =



Now, if you want your bindingHandler to play nice with and without AMD, it will instead look something like..

(function (factory) {
   
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
        factory
(require("knockout"), exports);
   
} else if (typeof define === "function" && define["amd"]) {
        define
(["knockout"], factory);
   
} else {
        factory
(ko);
   
}
}(function (ko){
    ko
.bindingHandlers.someThing =

 

That's not a very nice extensibility API.

Again, I'm sure there a way to have both "ko" and AMD working together, and I would like to know the best way.

Thirdly, looking at http://knockoutjs.com/documentation/amd-loading.html, the final example shows how a binding handler is added as a dependency to a viewmodel.



define
(['knockout-x.y.z', 'customBindingHandlers/hasFocus'], function(ko) {
 
return function appViewModel(){
 
...
 
// Add an editingName observable
 
this.editingName = ko.observable();
 
};
});



IMHO, that's just not right. The binding is view concern, not a viewmodel concern. It's the view the depends on the hasFocus binding handler. The viewmodel shouldn't have to know.

End of rant.

/Gunnar

Keuller Magalhaes

unread,
Jul 3, 2014, 5:56:15 PM7/3/14
to knock...@googlegroups.com
Hi,

I'm with similar problem, I would like to know if is there Knockout version with AMD support. As a Gunnar said, Knockout is not exposed in AMD module.

Regards.

Gunnar Liljas

unread,
Jul 3, 2014, 6:03:03 PM7/3/14
to knock...@googlegroups.com
Well Knockout has AMD support. If AMD is active when knockout is loaded, Knockout will be defined as a module named "knockout", but it will not export  "ko" to the global scope, so everything that references "ko" will have to be loaded using AMD too.


--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Márton Balassa

unread,
Jul 4, 2014, 5:28:40 AM7/4/14
to knock...@googlegroups.com
Again, I would recommend checking out Durandal, it's a very sophisticated SPA framework using Knockout and AMD modules.

Gunnar Liljas

unread,
Jul 4, 2014, 12:12:45 PM7/4/14
to knock...@googlegroups.com
Thanks for your response, Márton.

Yes, Durandal is nice, but...

1. Its future is...bright but confusing, and Knockout will be dropped in the next big release. Durandal is merging with AngularJS.
2. It's a full framework, so it's best suited for greenfield development. This project is a couple of years old, with a huge code base, so it's very brownfield.
3. It doesn't address my problem and questions. Sorry.

/G


--
Reply all
Reply to author
Forward
0 new messages