I do not think I entirely grasp what you are trying to do, but let me
take a stab.
You wish to create re-usable Knockout modules, however certain facets
of them are bound to the DOM elements (specifically, the id="" on the
<script> tags for templates).
I am not entirely sure if Knockout or jQuery or any other library out
there looks at <script> tags, but you might consider going about this
with custom bindings. Here is what I would do.
first --
--- your templates are only pure javascript encapsulation if you go
with the jQuery Templates, if you go with the Knockout "template"
binding, you actually attach to a physical HTML DOM element. Use this
to your advantage.
in other words, assuming
<div id="firstDomElementToHaveModule" data-bind="template:
'alphaTemplate'" ></div>
<script type="text/x-javascript" id='alphaTemplate'>
template code
</script>
data-bind="template: 'alphaTemplate'" is able to reference the script
element of the same name, and at first pass I don't see anything
unique in knockout that would let it do this other than normal
javascript ID selectors. (my knowledge of javascript is about the same
as a preschooler's knowledge of a hadron collider, though)
What I infer from this is that script tags are dom elements, and can
therefore be treated as such in selecting. But even if they are not,
bind to the DIV and then let it bind to the <script>
(documentation :
http://knockoutjs.com/documentation/template-binding.html
)
Now then, on to number 2.
in custom bindings, you have 4 things passed.
element — The DOM element involved in this binding
valueAccessor — A JavaScript function that you can call to get the
current model property that is involved in this binding. Call this
without passing any parameters (i.e., call valueAccessor()) to get the
current model property value.
allBindingsAccessor — A JavaScript function that you can call to get
all the model properties bound to this DOM element. Like
valueAccessor, call it without any parameters to get the current bound
model properties.
viewModel — The original, top-level view model object that you
originally passed to ko.applyBindings
(
http://knockoutjs.com/documentation/custom-bindings.html)
element is your key thing here. element can reference the DOM element
that called the binding. So for instance, in one of my scenarios, I am
using the jQuery UI SelectMenu ancillary plugin. Every time the
<select> that it is bound to changes, I need to notify the plugin to
update its value, so I have this code.
ko.bindingHandlers.jqSelect= {
init: function(element, valueAccessor, allBindingsAccessor,
viewModel) {
// This will be called when the binding is first applied to an
element
// Set up any initial state, event handlers, etc. here
},
update: function(element, valueAccessor, allBindingsAccessor,
viewModel) {
// probably not very good code I have here, but it seems to be
working.
$(element).selectmenu('value','VALUE');
}
};
Now in my HTML, I have my dom element that looks like this.
<select id="custom-select-menu" data-bind="{other bindings native to
knockout... }, jqSelect" ></select>
because 'jqSelect' is my binding, and because it is attached to a DOM
element, it will pass that DOM element just like a javascript
selector. So my binding handler gets a DOM element with an ID of
"#custom-select-menu" that I can treat like a normal javascript or
html object.
I am experimenting with encapsulating logic, as well. You can see some
of my tests
Here :
http://jsfiddle.net/ciel/Bwxt3/
Here :
http://jsfiddle.net/ciel/CJ8fh/
I basically wrap my primary logic into a function call to something
called "Selector", then Selector has a function called
"selector(params)" that accepts data. This behaves kind of like an
object oriented constructor in that I can pass information through it
to build the view model. The outer function returns the inner function
as a variable, and the inner function returns the viewModel as a
variable. So calling up "Project.Selector(data)" will pass data into
my selector(params) function, and return the resultant viewModel with
all of the building logic hidden away.
In my example I am saving data using jQuery Storage Plugin to write to
the local storage cache on the browser, but you could easily pull HTML
files using $('selector').load(url) and passing in your HTML file. You
could build a binding to attach to where you wanted the data to load
into, then use the 'element' variable in the "init" or "update" part,
and call load on it. You could put the Html Filename as a static
parameter or you could embedd the HTML filename as part of the View
Model and have it returned. So you might do this like ...
<div data-bind="custom: extraFile.html"></div>
ko.bindingHandlers.custom = {
init: function(element, valueAccessor, allBindingsAccessor,
viewModel) {
// get the value of the bindings
var value = valueAccessor(), allBindings =
allBindingsAccessor();
// try to unwrap whatever we were passed.
var valueUnwrapped = ko.utils.unwrapObservable(value);
$(element).load(value); // value is the .html url that was
passed
}
};
or you might let it pass in options, like this..
<div data-bind="custom: { url: 'extraFile.html' }"></div>
ko.bindingHandlers.custom = {
init: function(element, valueAccessor, allBindingsAccessor,
viewModel) {
// get the value of the bindings
var value = valueAccessor(), allBindings =
allBindingsAccessor();
// try to unwrap whatever we were passed.
var valueUnwrapped = ko.utils.unwrapObservable(value);
var url = valueUnwrapped.url || ''; // url is empty if not
given..
$(element).load(url); // url is the .html url that was passed
}
};