A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/moreartyjs/moreartyjs/wiki/Binding below:

Binding · moreartyjs/moreartyjs Wiki · GitHub

Binding is a central component of Morearty.js library.

It is responsible for:

How bindings are used in Morearty

To create Morearty context initial state should be passed to Morearty.createContext(...) method. Morearty wraps it into binding and register change listener on it to be notified when re-rendering needs to be performed. This binding is accessible through ctx.getBinding() and points to the state's root. Sub-components receive bindings to the relevant sub-parts of the state by creating sub-bindings using binding.sub('sub.path') method.

Bindings are designed to work with Immutable.js. So, every time you get data from bindings, it's represented as primitives or immutable data structures. That means that some Immutable.js API knowledge is required to be able to use bindings effectively. Immutable.js is very powerful, easy to use, and quickly evolving library, see its page for documentation and tutorials.

Many binding methods accept subpath parameter. It may be specified as a string with . separators or as an array of strings and numbers, e.g. 'path.to.nested.location.1' or ['path', 'to', 'nested', 'location', 1] or even ['path', 'to', 'nested', 'location', '1'] due to Immutable's string indexes auto-coercion. In the examples below single string syntax will be used for better readability.

Bindings define a set of operations on data.

var immutableValue = binding.get();
// or
var immutableValueAtSubpath = binding.get('sub.path');
// directly
binding.set('key', 'value');

// or using a function
binding.update('optional.sub.path', function (immutableValue) {
  return immutableValue.set('key', 'value');
});
Deleting and clearing data
binding.remove('optional.sub.path');
// or
binding.clear('optional.sub.path');

The latter does coll.clear() on nested immutable collection preserving its type.

var optionalPreserveConflicting = true;
binding.merge('optional.sub.path', optionalPreserveConflicting, Immutable.Map({ 'key': 'new value' }));
Transactions and chaining

Most of operations about (except get) return this binding and allow chaining. But it's usually required to make a set of changes at once, only notifying listeners at the end (re-rendering once). This functionality reminds database transactions and can be used like this:

binding.atomically().
  set('key', 'new value').
  clear('sub.path').
  update(someAnotherBinding, 'another.sub.path', updateFunction).
  commit();

If you need to make changes silently (skipping listeners notification), pass { notify: false } options object to commit.

Explicit transactions can be cancelled.

If uncommitted transaction is cancelled, further commit will have no effect.

var tx = binding.atomically().set('key', 'new value');
tx.cancel();
tx.commit(); // no effect
tx.isCancelled(); // true

For committed transactions affected paths will be reverted to original values, overwriting any changes made after transaction has been committed.

binding.set('key', 'initial value');
var tx = binding.atomically().set('key', 'new value').commit();
binding.get('key'); // 'new value'
tx.cancel();
tx.isCancelled(); // true
binding.get('key'); // 'initial value'

Since version 0.7 Morearty renders asynchronously, i.e. it queues binding updates and renders them in one pass. This provides an implicit transaction and frees from the need to use the above API. Still, it's a good idea to use explicit transactions where appropriate to indicate that a set of changes should be applied atomically.

Sub-bindings are created using sub method:

var subBinding = binding.sub('sub.path');

Updates through sub-binding are visible to parent bindings and are fully synchronized:

subBinding.set('key', 'new value');
binding.get('sub.path.key'); // === 'new value'

There's not much to say about sub-bindings, they are easy and intuitive to use.

Yes, sub-bindings are cached. If you already requested sub-binding for a sub-path, then it won't be re-created and existing instance is returned. Literally:

binding.sub('sub.path') === binding.sub('sub.path'); // === true
// and moreover
binding.sub('sub.path') === binding.sub('sub').sub('path'); // === true

This is done for performance reasons to minimize objects garbage during render and simplify reasoning.

Bindings support attaching change listeners:

var listenerId = binding.addListener('optional.sub.path', function (changes) {
  // use changes.getPath/isValueChanged/getPreviousValue/etc methods
  // see API documentation for details
});

Listeners can be removed:

binding.removeListener(listenerId);

or enabled/disabled/disabled during an operation:

binding.disableListener(listenerId);
binding.enableListener(listenerId);
binding.withDisabledListener(listenerId, someOperationFunction);

For easier component lifecycle bound listeners creation see [Listening for state changes](Authoring components#listening-for-state-changes).

Attaching meta information

Meta information can be attached to bindings (i.e. state nodes). This allows to store data you don't want to put in the main state, e.g. validation info, history, and so on. Changes in meta state are considered in render phase.

Meta information is represented as a companion binding for a binding. Access it using meta method like this:

var metaBinding = binding.meta();

and then use like an ordinal binding. You can even attach metadata to metadata, if you like, or use it in transaction with binding it was produced by:

binding.atomically().
  set('key', 'value').
  clear('something').
  update(metaBinding, 'some metadata', updateFunction).
  commit();

The area of possibilities meta-bindings provide is still open, expect Morearty to deeper leverage them in the future. Currently, meta-bindings are used to store history in history module and will very likely be used for validation.

Notice that meta state is not synchronized automatically, e.g. when you delete a state node, its meta value doesn't change. So, you will get same meta value on state node re-creation. This is for simplicity and performance reasons. All synchronization should be done by the user, if required.

Meta binding uses custom format to prevent values interfering between different state nodes:

{
  __meta__: <root meta>,
  foo: {
    __meta__: <foo meta>,
    bar: {
      __meta__: <bar meta>
    }
  },
  baz: {
    __meta__: <baz meta>
  }
}

So, meta state for path x resides at path x.__meta__.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4