Knockout debugging

There are chrome extension available but we can use a very basic statement;

console.log("View model: " + ko.toJSON(dataVM));

If we are dealing with array then;

console.log(dataVM()[0]);

If we want to unwrap a view model then (make sure you have created the view model with ko.mapping.fromJS method;

var dataVMUnwrap = ko.mapping.toJS(dataVM);
//convert view model back to js
console.log(JSON.stringify(dataVMUnwrap));

What is the difference between $root and $parent in Knockout?

They are similar but different:

  • $root refers to the view model applied to the DOM with ko.applyBindings;
  • $parent refers to the immediate outer scope;

Or, visually, from $data‘s perspective:

Or, in words of the relevant documentation:

  • $parent: This is the view model object in the parent context, the one immeditely outside the current context.
  • $root: This is the main view model object in the root context, i.e., the topmost parent context. It’s usually the object that was passed to ko.applyBindings. It is equivalent to $parents[$parents.length - 1].
  • $data: This is the view model object in the current context. In the root context, $data and $root are equivalent.

You’ll only see a practical difference if you have view models nested more than one level, otherwise they will amount to the same thing.

It benefit is rather simple to demonstrate:

var Person = function(name) {
  var self = this;
  self.name = ko.observable(name);
  self.children = ko.observableArray([]);
}
  
var ViewModel = function() {
  var self = this;
  self.name = 'root view model';
  self.mainPerson = ko.observable();
}

var vm = new ViewModel(),
    grandpa = new Person('grandpa'),
    daddy = new Person('daddy'),
    son1 = new Person('marc'),
    son2 = new Person('john');

vm.mainPerson(grandpa);
grandpa.children.push(daddy);
daddy.children.push(son1);
daddy.children.push(son2);

ko.applyBindings(vm);
th, td { padding: 10px; border: 1px solid gray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<script type="text/html" id="person">
  <tr>
    <td data-bind="text: $root.name"></td>
    <td data-bind="text: $parent.name"></td>
    <td data-bind="text: $data.name"></td>
  </tr>
  <!-- ko template: { name: 'person', foreach: children } --><!-- /ko -->
</script>

<table>
  <tr>
    <th>$root</th>
    <th>$parent</th>
    <th>$data</th>
  </tr>
  <!-- ko template: { name: 'person', data: mainPerson } --><!-- /ko -->
</table>

The $root is always the same. The $parent is different, depending on how deeply nested you are.

Here is another good example on StackOverflow.

Knockout Boolean binding not working

Here’s a quick fix if you’re doing data binding in knockout and wondering why a binding like the following isn’t working:

<div data-bind="visible: !isMessageHidden">

<script>
// In your view model
self.isMessageHidden: ko.observable(true) };
// ...
</script>

You need to add a set of parentheses after the isMessageHidden like so.

<div data-bind="visible: !isMessageHidden()">any message</div>

The key to understanding this is understanding that isMessageHidden is not a boolean value, but an observable which stores a boolean value. If we simply refer to this observable by name in our data-binding code, then knockout will infer that we want to retrieve the stored value. However, if we wish to refer to the stored value within a statement, such as !isMessageHidden(), then the parentheses are required in order to indicate that we want the stored value and not the observable itself. This tripped me up a few times when I was learning Knockout.

Knockout fromJS simple example

Define a view model;

var mappedViewmodel = ko.mapping.fromJS({
            name: 'Shahzad Khan',
            age: 55
        });
        ko.applyBindings(mappedViewmodel, document.getElementById("simpleData"));

Display on page;

<div class="col-sm-6">
    <h3 class="text-left">Knockout fromJS simple example</h3>
        <div id="simpleData">
            <p>name: <label data-bind="text: name" /></p>
            <p>age: <label data-bind="text: age" /></p>
        </div>
</div>

Another good tutorial is here

https://bsscommerce.com/confluence/knockout-js/

Read more here