0

With the click of a button, I want to update a d3js plot based on the values of two select elements. If I understand it right, simply calling the valueAccessor should fire off the update function, which is not happening in my code.

I have the following custom binding:

ko.bindingHandlers.plotSvg = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        valueAccessor();
        console.log("Update d3js plot");
    }
};

And the view:

    <div class="panel-body">
        <div class="row">
            <div class="col-xs-2">
                <select class="form-control"
                        data-bind="options: $root.options,
                                           optionsText: 'name',
                                           value: firstSelectedOption">
                </select>
            </div>
            <div class="col-xs-2">
                <select class="form-control"
                        data-bind="options: $root.options,
                                           optionsText: 'name',
                                           value: secondSelectedOption">
                </select>
            </div>
            <div class="col-xs-2 col-xs-offset-5">
                <button class="btn btn-primary" data-bind="click: updatePlot">
                    Visualise
                </button>
            </div>
        </div>
        <div data-bind="plotSvg: updatePlot"></div>
    </div>

updatePlot is a function in the viewmodel, and all it does is print a value at the moment.

edit The javascript: http://pastebin.com/2qKLf6yf The view: http://pastebin.com/TPvmKgxL

user2374668
  • 167
  • 1
  • 3
  • 10

2 Answers2

2

<div data-bind="plotSvg: updatePlot"></div> needs to reference a computed, otherwise knockout won't know when the value of something has changed and thus will never fire the custom binding's update method.

I'd recommend something like:

<div data-bind="plotSvg: selectedValue"></div>

and

ko.bindingHandlers.plotSvg = {
    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        viewModel.redrawPlot();
        console.log("Update d3js plot");
    }
};

where selectedValue is a computed that tracks currently selected value on your form, and gets updated when the button is clicked.

Since you're using two values, you can do something like this in your viewModel to trigger an observable change:

this.selectedValue = ko.observable(null);
this.updatePlot = function(){
    this.selectedValue(this.firstSelectedOption()+""+this.secondSelectedOption()+"")
}

Doing it this way will ensure its a unique string each time one of the options change. If neither change, then the observable won't change, and the plot shouldn't redraw. Its brute force, but it should work with what you have setup.

TheRightChoyce
  • 3,054
  • 1
  • 22
  • 19
  • This would mean that the plot would update on select change, which I don't want. I'd like to update the plot on the click of a button. – user2374668 Dec 09 '15 at 21:16
  • Honestly, hard to tell what exactly is being used on the plot = ) You can make `selectedValue` change on button click rather than select change.. its just an observable. I'll update above with an example – TheRightChoyce Dec 09 '15 at 23:42
  • _You can make selectedValue change on button click rather than select change_ Ah! That worked. Thanks for the nice solution! – user2374668 Dec 10 '15 at 07:17
1

When you call valueAccessor() you just get the value of the accessor dont, so to call the function try this : valueAccessor()().

  • 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. To easily accept both observable and plain values, call ko.unwrap on the returned value.

Ref. http://knockoutjs.com/documentation/custom-bindings.html

Community
  • 1
  • 1
Joel R Michaliszen
  • 4,164
  • 1
  • 21
  • 28