9
votes

Trying to get basic Knockout click binding set up, as per the example below:

<button id="btn-a" class="btn" data-bind="css: {'btn-primary':mode() == 'manual'}, click: $root.mode('manual')">Manual</button>
<button id="btn-b"  class="btn" data-bind="css: {'btn-primary':mode() == 'automatic'}, click: $root.mode('automatic')">Automatic</button>

<label>MODE: </label><span data-bind="text:mode()"></span>  

<script>

$(function () {

    var TestModel = function() {        
        var self = this;
        this.mode = ko.observable('manual');
    };

    var testModel = new TestModel();
    window.testModel = testModel;
    ko.applyBindings(testModel);

});

Fiddle: http://jsfiddle.net/aq85wk65/

However, running into two issues:

  1. The binding causes the mode() value to start out as 'automatic', even though we explicitly initialize it to 'manual'.
  2. Whenever a button is clicked, the javascript console shows:

Uncaught TypeError: h.apply is not a function

3

3 Answers

20
votes

You need to wrap your click handlers in function:

http://jsfiddle.net/aq85wk65/1/

<button id="btn-a" class="btn" data-bind="css: {'btn-primary':mode() == 'manual'}, click: function(){$root.mode('manual')}">Manual</button>

see http://knockoutjs.com/documentation/click-binding.html

6
votes

The problem is that your click handler is invoking the function instead of using its reference.

That's why you're ending up with mode being auto, because click: $root.mode('automatic') is setting the observable value.

Try this instead:

click: $root.mode.bind($root, 'manual')
3
votes

Either the .bind answer or the function() {} answer will work; but generally I prefer to avoid defining functions in my views where possible, and instead move that logic to the ViewModel.

So another option, and the one I'd probably go with in this case is to define a viewModel.setToManual() function and a viewModel.setToAutomatic() function.

Then the binding handler would just be

click: setToAutomatic

Not only is that cleaner in the view, but it protects the view against changes to the ViewModel's structure as well, as long as the behavior of setToAutomatic (and probably a comparable isAutomatic) are preserved.