Reputation: 5239
I have a list of knockout components
<!-- ko foreach: myComponents -->
<div data-bind="component: $data"></div>
<!-- /ko-->
Here's how I create my observable array of component definitions and this renders as expected.
createComponents = function(jsonData) {
var components;
components = _.map(jsonData, function( jsonItem ) {
switch (jsonItem.type) {
case 0:
return {
name: "component-type-0",
params: jsonItem
};
case 1:
return {
name: "component-type-1",
params: jsonItem
};
default:
throw new Error("No case for type " + jsonItem.type);
});
this.myComponents( components );
};
However I'm not sure how to sort them. My array only has the name
and the jsonData
but not the viewModel that's created when the component is created.
I'd like the items in the array to remain as components so to keep them easily reusable.
Is there a way to access the viewModel that is created so I can sort based on a property of that?
Upvotes: 1
Views: 954
Reputation: 16688
By the next version of Knockout, there might be a way to access to the component view model from the parent, but it's not part of Knockout at present. (See https://github.com/knockout/knockout/issues/1475 and https://github.com/knockout/knockout/issues/1533)
I've come up with a way to include a callback for component bindings that's called with the component view model.
Here is an example of it working to sort a set of components: http://jsfiddle.net/mbest/a6f3fmzt/
The first part is a custom binding that takes a callback
parameter and injects it into the params
value for the component
binding.
ko.bindingHandlers.componentWithCallback = {
init: function(element, valueAccessor, ignored1, ignored2, bindingContext) {
function newValueAccessor() {
var value = ko.unwrap(valueAccessor());
if (value.callback) {
value.params = ko.utils.extend(
{ callback: value.callback },
value.params);
}
return value;
}
ko.applyBindingAccessorsToNode(
element, { component: newValueAccessor }, bindingContext);
}
};
The second part is to wrap the component loader to call the callback function once the view model instance is created.
ko.components.defaultLoader.loadViewModel = (function (original) {
return function (errorCallback, viewModelConfig, callback) {
function newCallback(createViewModel) {
return callback(function (params, componentInfo) {
var componentVM = createViewModel.call(this, params, componentInfo);
if (params.callback) {
params.callback.call(null, componentVM);
}
return componentVM;
});
}
return original.call(this, errorCallback, viewModelConfig, newCallback);
}
}(ko.components.defaultLoader.loadViewModel));
Upvotes: 2