Reputation: 584
Let's say there is a simple HTML template:
<div>
<content-a></content-a>
<content-b></content-b>
</div>
I register both components using (example for component "content-a"):
ko.components.register('content-a', {
viewModel: { instance: vm }, // ViewModel for that component
template: template // template of that component
});
Then later I inject HTML template into specified HTML element:
var node = document.getElementById('content');
node.innerHTML = template; // here "template" represent just a HTML string (described at the very top)
ko.applyBindings(vm, node); // here vm represents ViewModel instance
However, all registered components are rendered when I apply bindings.
Is there a way to render components on demand? Not when applyBindings is applied.
In other words: I'd like to render main content, applyBindings and then later on demand add and render new components.
Upvotes: 1
Views: 1638
Reputation: 2851
I stumbled across this post as it described something similar to a problem I had. We bind the view model to a specific element as it may or may not exist; to get the component to bind, I just piggy back off this, here is how I achieved this:
Have a collection to store elements you which to mind
var self = this;
self.modulesToLoad = [];
self.elements = [];
Check to see if the element exists with a small function
self.checkIfElementExists = function (element, viewModel) {
if (element != undefined) {
self.modulesToLoad.push(viewModel);
self.elements.push(element);
}
};
Declare your component
ko.components.register("custom-component", {
template: { require: "text!Components/custom-component/custom-component.html" },
viewModel: { require: "Components/custom-component/custom-component" }
});
Add to collection which checks to see if element exists
self.checkIfElementExists($("custom-component")[0],
"Components/custom-component/custom-component"); // A little bit of repetition here, but do you care?
Finally loop through the collection
for(var i = 0; i < elements.length; i++) {
var viewModel = new arguments[i]();
var element = elements[i];
ko.applyBindings(viewModel, element);
}
Upvotes: 1
Reputation: 14995
By default all of your components that are added to the DOM are shown. If you wanted to hide them until a specific condition is met you can do so like this -
yourView.html -
<section class="sales" data-bind="visible: isRendered">
<div data-bind="text: sales"></div>
</section>
yourViewModel.js -
define([], function () {
return {
isRendered: ko.observable(false),
sales: ko.observable()
}
});
Component registration -
ko.components.register('yourComponent', {
viewModel: { require: 'files/yourViewModel' },
template: { require: 'text!files/yourView.html' }
});
And then later you could change the value of your components isRendered observable to make it be shown -
vm.isRendered(true);
Of course this is all pseudo-code but if you made a working fiddle for what you are trying to do I could help explain more there. My code above shows how you could build a component out using a module loader but hopefully it should make sense.
Upvotes: 0