An open API service indexing awesome lists of open source software.

https://github.com/danielearwicker/knockout.clear

Minimal utilities to make it easy to get KnockoutJS to clear up garbage automatically
https://github.com/danielearwicker/knockout.clear

Last synced: 3 months ago
JSON representation

Minimal utilities to make it easy to get KnockoutJS to clear up garbage automatically

Awesome Lists containing this project

README

          

# knockout.clear
*Minimal utilities to make it easy to get KnockoutJS to clear up garbage automatically*

## Motivation

* [Introductory blog post](https://smellegantcode.wordpress.com/2015/02/21/knockout-clear-fully-automatic-cleanup-in-knockoutjs-3-3/)
* [Initial discussion](https://groups.google.com/d/msg/knockoutjs/uYCyGs2hb2k/Y_5sd9rLRXcJ)

In brief, with the introduction of `ko.pureComputed` it should not be necessary to manually dispose of anything in Knockout:

* Only use `ko.pureComputed` and when your observables are not subscribed to, they will not subscribe to anything else and so will not be kept alive unnecessarily.
* Well-behaved bindings will call `ko.cleanNode` on DOM elements before they are discarded, which will make them unsubscribe from your observables.

The only hitch is the need to trigger side-effects that don't return values. A `pureComputed` won't do this unless it is `awake`, and to be awake it needs to be subscribed to.

One major application of side-effects is the need to make asynchronously-obtained values (such as promises) appear like ordinary observables.

This library defines the building blocks for dealing with side-effects within the framework of `pureComputed`, and builds on the resulting pattern to provide an easy way to consume promises.

## Usage

All you need is:

* [Knockout 3.3](http://knockoutjs.com) or later
* The single file [lib/knockout.clear.js](https://github.com/danielearwicker/knockout.clear/blob/master/lib/knockout.clear.js) from the knockout.clear repository.

The other stuff in the repository is mostly unit tests.

If you're into bower:

bower install danielearwicker/knockout.clear

Note that this library assumes `ko` is a global so it can extend it. If there's a more flexible way to arrange it, I'm open to suggestions.

If you're into TypeScript (entirely optional), you'll also want:

* [typings/knockout.clear/knockout.clear.d.ts](https://github.com/danielearwicker/knockout.clear/blob/master/typings/knockout.clear/knockout.clear.d.ts)

## The `execute` binding

The `execute` binding is useful when you want to create a `ko.pureComputed` that acts as a side-effecting function that re-executes when its dependencies change, but doesn't return a value and would not normally be depended on by anything else.

To keep it awake, first you add it to your view model:

var viewModel = {
pointlessLogging: ko.pureComputed(function() {
console.log("Phone number is: " + phoneNumber());
})
};

Then you bind to it in your HTML:

That's it. When you have a simple viewModel/HTML scenario, this is the easy way to keep your `pureComputed` re-executing as long as the view is on the page.

For more advanced situations, you might need the API.

## API

*Note: The TypeScript declarations are presented here as a precise reference, but this library is not actually written in TypeScript and does not depend on it. Code samples are both valid JavaScript and TypeScript.*

---

### `ko.execute`

execute(
pureComputed: KnockoutComputed,
evaluatorFunction: () => T,
thisObj?: any): KnockoutComputed;

`ko.execute` is used as an alternative to the `execute` binding described above, in situations where you can't (or don't want to) simply modify the HTML bindings.

This is typically in situations where you're building a reusable fragment of a model containing observable data, but you don't want to force your users to use the `execute` binding. See `ko.unpromise` in this library for an example.

To control when the `evaluatorFunction` should be actively re-executing, you must supply a `pureComputed` as the first argument (an `Error` is thrown otherwise).

The `evaluatorFunction` typically returns `void`, though it doesn't have to. It must not depend on the `pureComputed` that you supplied as the first argument (ideally an error would be thrown if this condition is violated but there doesn't appear to be a way to do that currently).

ko.execute(lastName, function() {
console.log("Phone number is: " + phoneNumber());
});

The returned object is a `pureComputed`, on which you can call the `extend` function if necessary. Otherwise, you don't need to keep a reference to it and you don't need to manually dispose it.

---

### `ko.unpromise`

unpromise(evaluatorFunction: () => T | KnockoutExecuteThenable,
options?: {
initialValue?: T;
errorValue?: T;
thisArg?: any;
}): KnockoutComputed;

`ko.unpromise` creates a `pureComputed` that automatically converts promises (or indeed anything vaguely promise-like) into plain values.

The `evaluatorFunction` will likely depend on other observables which act as parameters to some API that returns a promise, e.g. using jQuery if you like:

var text = ko.unpromise(function() {
return $.get('page/' + selectedPageName());
});

The value of `text` will initially be `undefined`, but a short time later the asynchronous `$.get` will complete and `text` will change its value to the returned data. It acts just like any other `pureComputed` so you can bind to it or read it from other `pureComputed`s.

You can change the default values by passing options:

var text = ko.unpromise(function() {
return $.get("messages/" + selectedMessage());
}, {
initialValue: "Please wait...",
errorValue: "Message could not be loaded"
});

If `errorValue` is not specified, `initialValue` is used.

---

### `ko.isPureComputed`

isPureComputed(obs: any): boolean;

Returns true if the argument was created with `ko.pureComputed`.

Note: It is possible to create a `pureComputed` by calling `ko.computed` and passing `pure: true`, but this function cannot detect that. Consequently you cannot use such objects as the the first argument to `ko.execute`.

There is a plausible excuse for this: strive to only use `ko.pureComputed`, so that you can easily search your code for any remaining uses of `ko.computed` and regard them as suspicious.

## Running the tests

Install node and grunt-cli. Clone this repository and install it:

git clone http://github.com/danielearwicker/knockout.clear.git
cd knockout.clear
npm install

That will run the command-line tests. There is a further minor test for the `execute` binding that you can run by opening the runner page in your browser:

spec/runner.html

Note that all the Knockout 3.3 tests will also run! This is important because `knockout.clear` patches and wraps a couple of things (see the source for details).

## Acknowledgements

Many thanks to [Michael Best](https://github.com/mbest) for invaluable pointers.