JavaScript MIT

knockback

Knockback.js provides Knockout.js magic for Backbone.js Models and Collections.

K

kmalakoff

Dernière activité 11 janv. 2026
kmalakoff/knockback

1,1 k

étoiles

69

forks

7

issues ouvertes

Ce README est souvent en anglais.

logo

Knockback.js provides Knockout.js magic for Backbone.js Models and Collections.

Why Knockback?

  • Make amazingly dynamic applications by applying a small number of simple principles
  • Leverage the wonderful work from both the Backbone and Knockout communities
  • Full TypeScript support with type definitions included

Installation

npm install knockback

Peer Dependencies

Knockback requires these peer dependencies:

npm install backbone knockout underscore

Examples

Simple

The HTML:

<label>First Name: </label><input data-bind="value: first_name, valueUpdate: 'keyup'" />
<label>Last Name: </label><input data-bind="value: last_name, valueUpdate: 'keyup'" />

And...engage:

import Backbone from 'backbone';
import ko from 'knockout';
import kb from '@mcpeasy/knockback';

const model = new Backbone.Model({ first_name: 'Bob', last_name: 'Smith' });
ko.applyBindings(kb.viewModel(model));

When you type in the input boxes, the values are properly transferred bi-directionally to the model and all other bound view models!

Advanced

The View Model:

import Backbone from 'backbone';
import ko from 'knockout';
import kb from '@mcpeasy/knockback';

// Create a model
const model = new Backbone.Model({ first_name: 'Bob', last_name: 'Smith' });

interface PersonViewModel {
  first_name: ko.Observable<string>;
  last_name: ko.Observable<string>;
  full_name: ko.Computed<string>;
}

// Create a view model with a computed property
const vm = kb.viewModel<PersonViewModel>(model, {
  extend: (vm) => ({
    full_name: ko.computed(() => `${vm.first_name()} ${vm.last_name()}`);
  }),
});

// Apply bindings
ko.applyBindings(vm);

// ... do stuff then clean up
vm.dispose();

Named imports are also supported if you prefer them:

```typescript
import { viewModel } from '@mcpeasy/knockback';

const vm = viewModel<PersonViewModel>(model);
vm.dispose();

// dispose() is attached automatically and is called by releaseOnNodeRemove / KO component disposal. // You no longer call destroy() manually.


You can also pass `extend` as a plain object if you prefer:

```typescript
const vm = kb.viewModel<PersonViewModel>(model, {
  extend: {
    full_name: ko.computed(() => `${model.get('first_name')} ${model.get('last_name')}`),
  },
});

The HTML:

<h1 data-bind="text: 'Hello ' + full_name()"></h1>
<label>First Name: </label><input data-bind="value: first_name, valueUpdate: 'keyup'" />
<label>Last Name: </label><input data-bind="value: last_name, valueUpdate: 'keyup'" />

Now, the greeting updates as you type!

Breaking Changes in v2.0

Knockback v2.0 uses modern TypeScript conventions. All option names and API properties have been changed from snake_case to camelCase:

Core Options:

Old (v1.x) New (v2.0)
static_defaults staticDefaults
event_watcher eventWatcher
view_model viewModel
models_only modelsOnly
auto_compact autoCompact
sort_attribute sortAttribute

Plugin Options:

Old (v1.x) New (v2.0) Plugin
kb.locale_manager kb.localeManager Localization
event_selector eventSelector Triggering
validation_options validationOptions Validation
no_attach noAttach Validation
$error_count $errorCount Validation
$active_error $activeError Validation

Migration example:

// v1.x (old)
const co = kb.collectionObservable(collection, {
  view_model: PersonViewModel,
  sort_attribute: 'name',
  auto_compact: true,
});

// v2.0 (new)
const co = kb.collectionObservable(collection, {
  viewModel: PersonViewModel,
  sortAttribute: 'name',
  autoCompact: true,
});

API

Core Functions

  • observable(model, key, options?) - Create an observable bound to a model attribute
  • viewModel(model, options?) - Create observables for all model attributes
  • collectionObservable(collection, options?) - Create an observable array bound to a collection
  • dispose() - Attached to view models/observables; called by releaseOnNodeRemove and KO component disposal
  • dispose(obj) - Helper to dispose plain objects that contain Knockback observables

Plugins

  • defaultObservable<T>(observable, defaultValue) - Provide default values
  • formattedObservable(format, ...args) - Two-way string formatting
  • localizedObservable(value, options) - Locale-aware observables

Localization (typed)

import kb from '@mcpeasy/knockback';
import type { LocaleManager } from '@mcpeasy/knockback';

class MyLocaleManager implements LocaleManager {
  get(id: string): string {
    return id;
  }
  getLocale(): string {
    return 'en';
  }
  setLocale(_locale: string): void {}
}

kb.setLocaleManager(new MyLocaleManager());
const localeManager = kb.getLocaleManager<MyLocaleManager>();

Leak checks with Statistics

const stats = new kb.Statistics();
kb.setStatistics(stats);

const before = stats.snapshot();
// ... route change + dispose old page ...
const after = stats.snapshot();

const delta = stats.diff(before, after);
console.log(delta);
  • triggeredObservable(emitter, event) - Event-based observable updates
  • valueValidator(observable, validators) - Value validation

Documentation

Dependencies

Contributing

To build the library:

npm run build

To run tests:

npm test

License

MIT

Projets similaires

Give your JS App some Backbone with Models, Views, Collections, and Events

JavaScript
Jjashkenas
28,1 k étoiles5,3 k

Knockout makes it easier to create rich, responsive UIs with JavaScript

JavaScriptdata-bindingjavascriptknockout
Kknockout
10,6 k étoiles1,5 k

Marionette v4 for Backbone applications. Maintenance fixes; new development continues in marionettejs/marionette.

JavaScriptbackbonebackbone-frameworkframework
Mmarionettejs
7 k étoiles1,2 k