Reputation: 75
I am trying to create a custom Knockout component to wrap around a Google Chart's graph (or any chart library for that matter).
Ideally I would like to make a component with a viewmodel that holds the graph data. Once that component is bound using a custom binding, whenever the update function is called I would access that array with the data, add the new value, and tell the graph to redraw.
The problem is when I am inside the update function of the bindinghandler, I cannot see the graph's view model. How can I access this?
Component:
ko.components.register('line-graph', {
viewModel: function(params) {
var self = this;
self.data = new google.visualization.DataTable(
{
cols: [{id: 'index', label: '', type: 'number'},
{id: 'value', label: '', type: 'number'}]
}, 0.6);
self.currentPoint = 1;
self.lastValue = null;
},
template:
'<div></div>'
});
Binding:
ko.bindingHandlers.lineGraph = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
},
update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var observable = valueAccessor();
if(observable != null){
//Here, the viewmodel and all properties of the bindingContext correspond to the main viewmodel, not the graph's viewmodel
viewModel.data.addRow([viewModel.currentPoint++, value]);
drawChart();
}
viewModel.lastValue = value;
}
}
Update: Here is how I plan to use the binding. The pressureValue variable would be a value in my main viewmodel that is being updated constantly in the background.
<line-graph data-bind="lineGraph: pressureValue"></line-graph>
Any thoughts? Am I approaching this incorrectly?
Upvotes: 0
Views: 6872
Reputation: 2238
You should be able to use ko.dataFor(element) or ko.contextFor(element) from inside the update function to get the ViewModel.
See http://knockoutjs.com/documentation/unobtrusive-event-handling.html for documentation and an example.
Edit: Turns out this doesn't work if you put the binding directly on the component. For the proper solution see Robert Slaney's answer.
Upvotes: 1
Reputation: 3722
You are combining two different concepts here.
When using the new component feature of Knockout the data-bind syntax is different
refer to : http://knockoutjs.com/documentation/component-custom-elements.html
<line-graph params="value: pressureValue"></line-graph>
or
<div data-bind="component: {name: 'line-graph', params: {value: pressureValue}}"></div>
Knockout will invoke your component and replace the contents of your custom element with the DOM you supply from the template value. In your case, the template is an empty DIV with no data-bind. At no point is your custom binding invoked.
Your component should now have the pressureValue observable sent into the viewModel function as the params argument.
I think, based on what your custom binding is expected, you need to add this "value" to the viewModel
viewModel: function(params) {
...
self.value = params.value;
}
Your template of the component should now become ( where $data is the value of the object returned from the viewModel function of the component )
template: '<div data-bind="lineGraph: $data.value"><div>'
This should now fire your custom binding and, hopefully, get the result you expect.
I think there is still something missing from your samples above as the variable value
in your update binding is declared anywhere, should that have been observable
. A bit of tweaking will be required but the basic data flow above should be what you need.
Please let me know if I'm on the right track...
Upvotes: 3