Getting Started with Knockback.js: Knockback.js Important Details

#Inheritance Some Knockback classes are meant to be inherited from. Specifically:

When using CoffeeScript, you can derive from a super class using:

class YourClass extends SuperClass
  # extensions

or when using JavaScript, you can derive from a super class using:

var YourClass = SuperClass.extend({
  /* extensions */
})

For example:

<div id='kb_view_model_inheritance'>
  <p>First name: <input class='input-small pull-right' data-bind="value: first_name, valueUpdate: 'keyup'" /></p>
  <p>Last name: <input class='input-small pull-right' data-bind="value: last_name, valueUpdate: 'keyup'" /></p>
  <p>Hello, <span data-bind="text: full_name"> </span>!</p>
</div>
model = new Backbone.Model({first_name: "Planet", last_name: "Earth"})

class MyViewModel extends kb.ViewModel
  constructor: (model) ->
    super
    @full_name = ko.computed((->return "#{@first_name()} #{@last_name()}"), @)
view_model = new MyViewModel(model)

ko.applyBindings(view_model, $('#kb_view_model_inheritance')[0])
var ko = kb.ko;

var model = new Backbone.Model({first_name: "Planet", last_name: "Earth"});

var MyViewModel = kb.ViewModel.extend({
  constructor: function(model) {
    kb.ViewModel.prototype.constructor.apply(this, arguments);
    this.full_name = ko.computed((function() {
      return "" + (this.first_name()) + " " + (this.last_name());
    }), this);
  }
});

var view_model = new MyViewModel(model);

ko.applyBindings(view_model, $('#kb_view_model_inheritance')[0]);

Live Result

First name:

Last name:

Hello, !

#Specifying Mappings Paths for Nested Models

Because Backbone.Models can have attributes than contain nested Backbone.Models or Backbone.Collections, there are times where you need to specialize the ViewModel you want to use; for example, in a model/collection hierachy with relationships. When you do need to, you can use the factories option when creating a kb.ViewModel or kb.CollectionObservable

view_model = {
  people: kb.collectionObservable(new Backbone.Collection([bob, fred]), {
    factories:
      'models': PersonViewModel
      'models.friends.models': FriendViewModel
  })
}
var view_model = {
  people: kb.collectionObservable(new Backbone.Collection([bob, fred]), {
    factories: {
      'models': PersonViewModel,
      'models.friends.models': FriendViewModel
    }
  })
};

Please take a look at the Nested Model Tutorial for more details.

#Knockout Observables Foundations

Many Knockback.js classes return Knockout.js observables so their dependencies/subscriptions can and should be managed like any Knockout observable. This is **very important if you choose to extend Knockback classes.

These classes return a ko.observable instead of 'this':

Use ko.utils.wrappedObservable(this) or return the constructor result if you dervive from them:

YourCollectionObservable = kb.CollectionObservable.extend({
  constructor: function(collection, options) {
    return kb.CollectionObservable.prototype.constructor.call(this, collection, { view_model: YourViewModel, options: options });
  }
});

or

YourCollectionObservable = kb.CollectionObservable.extend({
  constructor: function(collection, options) {
    kb.CollectionObservable.prototype.constructor.call(this, collection, { view_model: YourViewModel, options: options });
    return ko.utils.wrappedObservable(this);
  }
});

These classes return 'this':

#Backbone.Model Signatures

Knockback.js does not require Backbone.Models or Backbone.ModelRefs for attribute watching, but requires only Backbone.Model-like signature.

The minimal Backbone.Model signature is:

  • Backbone.Events: 'bind(event, callback)', 'unbind(event, callback)', and 'trigger(event, params...)'
  • Backbone.Model: 'get(attribute_name)'
  • Triggering: 'change' and/or "change:attribute_name" events when the Backbone.Models-like instance's attributes change.

This fact is used when implementing a Custom Locale Manager and could be used to port another library like Spine.js to Knockback.js.