nomen
nomen

Reputation: 3715

Knockout: Can't parse binding

I'm having a problem with Knockout. It is telling me that it can't parse a specific binding. If I don't include the binding in my HTML, the page compiles and I can run the event handler manually (in the console). Here is what the binding looks like:

<!-- ko foreach: problems -->
  <li data-bind="css: {active: $root.current.number() == $data.number() }">
    <a data-bind="click: $root.setCurrent( $data.number ), text: $data.number">
<!-- /ko -->

The error I get is the very unhelpful

"Unable to parse bindings. Bindings value: click: $root.setCurrent( $data.number ), text: $data.number Message: undefined is not a function"

Of course, $data is very clearly not undefined. If I remove the call to setCurrent, the bindings compile file, and I can run setCurrent in the console (and it works).

The setCurrent handler is defined in my view model as:

var ViewModel = function (data) {
  var self = this;
  ko.mapping.fromJS(data, {}, self);
}

$('document').ready( function () {
  $.getJSON("@{PracticalWriteR}", function (data) {
    viewModel = new ViewModel(data);

    pager.extendWithPage(viewModel);
    ko.applyBindings(viewModel);
    pager.start();
    viewModel.setCurrent = function (num) {
      viewModel.problems()[viewModel.current.number() - 1].response(viewModel.current.problem.response());
      viewModel.problems()[viewModel.current.number() - 1].marked(viewModel.current.problem.marked());

      var neu = viewModel.problems()[num - 1];
      viewModel.current.number(num);
      viewModel.current.problem.answers(neu.answers());
      viewModel.current.problem.response(neu.response());
      viewModel.current.problem.practical.key(neu.practical.key());
      viewModel.current.problem.practical.value.question(neu.practical.value.question());
      viewModel.current.problem.practical.value.solution(neu.practical.value.solution());
      viewModel.current.problem.marked(neu.marked());
      viewModel.current.problem.number(neu.number());
    };
  });
});

The idea is that setCurrent takes an int, which is a "question number" and changes first updates the current-current question, and then changes the current question to a new question (whose number is the original argument). Sorry for the noise here.

Upvotes: 0

Views: 197

Answers (1)

John-M
John-M

Reputation: 653

When you bind a function to an event in knockout you generally call the function without parenthesis (similar to how you would do using addEventListener).

Knockout automatically provides the current model object as the first parameter to the function, and then the actual DOM event that activated the binding as the second parameter.

Your code should work if you just change it to:

<a data-bind="click: $root.setCurrent, text: $data.number">

Then change your setCurrent function to accept the Object wrapping the number as its parameter.

You can modify this behavior by using an anonymous function if you want to alter the order or way in which parameters are passed... for your case you could do something like

<a data-bind="click: function(data, event) { $root.setCurrent($data.number) }, text: $data.number">

There is also yet another method, using the myFunction.bind(param1, param2, ...) syntax if you don't like the anonymous function.

See the knockout docs on click binding for more info: http://knockoutjs.com/documentation/click-binding.html

Upvotes: 2

Related Questions