#Tutorial: kb.Observable

Knockback.js provides ways to customize a kb.Observable when it is created. This tutorial provides working examples of using these options.

Create Options: {read: function(), write: function(value)}

Instead of performing a simple Backbone.Model get or set to synchronize with a kb.Observable, you can provide a custom read or write method like for a ko.observable.

Note: just like in Knockout.js, if you require access to the owning view model, it provided as 'this' in read and write methods if you provide it as a parameter to the kb.observable's create method: (model, options, owning_view_model)

<div id='kboo_read_write'>
  <input class='input-small pull-right' data-bind="value: formatted_number, valueUpdate: 'keyup'"/>
  <label data-bind="text: number"></label>
</div>
model = new Backbone.Model({number: 33})

ViewModel = (model) ->
  @number = kb.observable(model, 'number')
  @formatted_number = kb.observable(model, {
    key:'number'
    read: -> return "#: #{@number()}"
    write: (value) -> @number(value.substring(3))
  }, {}, @)
  return

view_model = new ViewModel(model)

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

var model = new Backbone.Model({number: 33});

var ViewModel = function(model) {
  this.number = kb.observable(model, 'number');
  this.formatted_number = kb.observable(model, {
    key: 'number',
    read: function() { return "#: " + (this.number()); },
    write: function(value) { return this.number(value.substring(3)); }
  }, {}, this);
};

var view_model = new ViewModel(model);

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

Live Result

Create Options: {localizer: constructor(value)}

Instead of a read and/or write option, you can provide a kb.LocalizedObservable derived class for custom localized of an attribute. Please see the kb.LocalizedObservable tutorial an explanation of the following:

ViewModel and Bindings:

model = new Backbone.Model({date: new Date()})

view_model =
  date: kb.observable(model, {key: 'date', localizer: LongDateLocalizer})
  var model = new Backbone.Model({date: new Date()});

  var view_model = {
    date: kb.observable(model, {key: 'date', localizer: LongDateLocalizer})
  };

Create Options: {default: value or observable}

You can pass a default function or parameter to provide a value when there is no value available.

<div id='kboo_default'>
  <p>Name: <input class='input-small pull-right' data-bind="value: name, valueUpdate: 'keyup'"/></p>
  <p>Name with default: <span data-bind="text: name_with_default"></span></p>
</div>
model = new Backbone.Model({})

ViewModel = (model) ->
  @name = kb.observable(model, 'name')
  @name_with_default = kb.observable(model, {key: 'name', default: '(no name)'})
  return

view_model = new ViewModel(model)

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

var model = new Backbone.Model({});

var ViewModel = function(model) {
  this.name = kb.observable(model, 'name');
  this.name_with_default = kb.observable(model, {key: 'name', "default": '(no name)'});
};

var view_model = new ViewModel(model);

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

Live Result

Name:

Name with default:

Dynamic Attribute Types

Since Knockback.js version 0.16.0, a kb.Observable can be created using the correct type before the attribute is loaded using the factories options and change types when the attribute value changes.

model = new Backbone.Model({reused: null})
view_model = kb.viewModel(model)
# view_model.reused is a ko.observable
# view_model.reused.valueType() is kb.TYPE_SIMPLE

model.set({reused: new Backbone.Model()})
# view_model.reused is a kb.ViewModel
# view_model.reused.valueType() is kb.TYPE_MODEL

model.set({reused: new Backbone.Collection()})
# view_model.reused is a kb.CollectionObservable
# view_model.reused.valueType() is kb.TYPE_COLLECTION
var model = new Backbone.Model({reused: null});
var view_model = kb.viewModel(model);
// view_model.reused is a ko.observable
// view_model.reused.valueType() is kb.TYPE_SIMPLE

model.set({reused: new Backbone.Model()})
// view_model.reused is a kb.ViewModel
// view_model.reused.valueType() is kb.TYPE_MODEL

model.set({reused: new Backbone.Collection()})
// view_model.reused is a kb.CollectionObservable
// view_model.reused.valueType() is kb.TYPE_COLLECTION