Upgrading to >= 0.15.0 from a previous version

New Stuff

  1. kb.ViewModel now handles nested models (like self-referencing Backbone-Relational.js models)

    class Person extends Backbone.RelationalModel
      relations: [{
        type: Backbone.HasMany
        key: 'friends'
        relatedModel: Person
      }]
      
    john = new Person({
      id: 'person-1'
      name: 'John'
      friends: ['person-2']
    })
    paul = new Person({
      id: 'person-2'
      name: 'Paul'
      friends: ['person-1']
    })
    
    john_view_model = kb.viewModel(john)
    
    friend_view_model = john_view_model.friends()[0]
    kb.utils.wrappedModel(friend_view_model)                      # paul
    kb.utils.wrappedModel(friend_view_model.friends()[0])         # john
    
    ...
    kb.utils.release(john_view_model); john_view_model = null     # release when done
    var Person = Backbone.RelationalModel.extend({
      relations: [{
        type: Backbone.HasMany,
        key: 'friends',
        relatedModel: Person
      }]
    });
    
    var john = new Person({
      id: 'person-1',
      name: 'John',
      friends: ['person-2']
    });
    var paul = new Person({
      id: 'person-2',
      name: 'Paul',
      friends: ['person-1']
    });
    
    var john_view_model = kb.viewModel(john);
    
    var friend_view_model = john_view_model.friends()[0];
    kb.utils.wrappedModel(friend_view_model);                     // paul
    kb.utils.wrappedModel(friend_view_model.friends()[0]);        // john
    
    ...
    kb.utils.release(john_view_model); john_view_model = null;    // release when done
    });

    Related Tutorials:

  2. kb.CollectionObservable is now a ko.observableArray so you no longer need to supply the second parameter

    # WAS:
    view_model =
      property: ko.observableArray()
      collection_observable: kb.collectionObservable(collection, observable_array, options)
      
    for model_view_model in view_model.property()
      ...
      
    # IS NOW:
    view_model =
      property: kb.collectionObservable(collection, options)
      
    for model_view_model in view_model.property()
      ...
    // WAS:
    var view_model = {
      property: ko.observableArray()
      collection_observable: kb.collectionObservable(collection, observable_array, options)
    };
    
    var view_model;
    for (var i = 0, len = view_model.property().length; i < len; i++) {
      view_model = view_model.property()[i];
      ...
    }
    
    // IS NOW:
    var view_model = {
      property: kb.collectionObservable(collection, options)
    };
    
    var view_model;
    for (var i = 0, len = view_model.property().length; i < len; i++) {
      view_model = view_model.property()[i];
      ...
    }
    

Required Changes

  1. kb.collectionObservable is now a ko.observableArray so you no longer need to supply the second parameter

    This means:

    • kb.collectionObservables will hold Models if a view_model-create option is not passed to the constructor (you can call hasViewModels() to check)
    • kb.collectionObservables::eachViewModel(callback) has been deprecated since you have direct access to the array of models or view models

    Required Changes:

    • Update custom sort functions to use kb.utils.wrappedModel(model)
      collection_observable = kb.collectionObservable(new Backbone.Collection([{name: 'name2'}, {name: 'name1'}]), {
        view_model:     kb.ViewModel
        sorted_index:   (models, model) -> return _.sortedIndex(models, model, (test) -> return kb.utils.wrappedModel(test).get('name') )
      })
      collection_observable = kb.collectionObservable(new Backbone.Collection([{name: 'name2'}, {name: 'name1'}]), {
        view_model: kb.ViewModel,
        sorted_index: function(models, model) {
          return _.sortedIndex(models, model, function(test) {
            return kb.utils.wrappedModel(test).get('name');
          });
        }
      });
    • Replace calls to kb.CollectionObservable::eachViewModel(callback) with direct iterations on the collection itself
      for view_model in collection_observable()
        # do something
      )
      var view_model;
      for (var i = 0, len = collection_observable().length; i < len; i++) {
        view_model = collection_observable()[i];
        // do something
      }
      
  2. kb.collectionObservable no longer triggers changes when model attributes change (only when the list of models is modified)

    Required Changes:

    • If you require triggering on model attribute changes, register with the collection and trigger them manually
      collection.bind('change', -> collection_observable.valueHasMutated())
      collection.bind('change', function(){ collection_observable.valueHasMutated(); });
      
  3. Utility functions have been moved to kb.utils to be more consistent with Knockout

    You can find all of the utility functions here

    Here is a list of the deprecated functions:

    • Knockback.wrappedObservable(instance)
        was replaced by kb.utils.wrappedObservable(instance {, observable})
    • Knockback.viewModelGetModel(view_model) and Knockback.vmModel(view_model)
        were replaced by kb.utils.wrappedObservable(view_model {, observable})
    • Knockback.vmRelease(view_model)
        was replaced by kb.utils.release(obj)
    • Knockback.vmReleaseObservable(observable)
        was replaced by kb.utils.release(obj)
  4. kb.LocalizedObservable now uses Backbone.extend for javascript inheritance so read/write options have been deprecated

    Required Changes:

    • Use Coffeescript class extends or JavaScript extend() for kb.LocalizedObservable
      class MyLocalizer extends kb.LocalizedObservable
        constructor: (value, options, view_model) ->
          super; return kb.utils.wrappedObservable(this)
        read: (value) ->
          # return something
        write: (localized_string, value) ->
          # do something
      MyLocalizer = kb.LocalizedObservable.extend({
        constructor: function(value, options, view_model) {
          kb.LocalizedObservable.prototype.constructor.apply(this, arguments);
          return kb.utils.wrappedObservable(this);
        },
        read: function(value) {
          # return something
        },
        write: function(localized_string, value) {
          # do something
        }
      });