The obBinder
factory provides the main public API for
the OmniBinder
module.
obBinder
is a factory whose instances can be used
in any scope to bind any of the scope's models to a protocol.
Each obBinder
instance is associated with one model in one scope.
The obBinder
should generally be treated as a static object,
as far as the Change Pipeline is concerned.
But it's useful to occasionally store temporary metadata
or temporary data on a binder.
For example, when model updates are being throttled,
it would be appropriate to store a temporary queue of
changes on the binder
to be batched in a later call to a protocol.
The binder
is accessible in every part of the Change Pipeline.
Using the obBinder
factory creates a new binding instance.
The factory takes the following arguments:
- Scope
scope
:required The scope in which to watch the model. - String
model
: required Name of the model to watch on the provided scope. - Protocol
protocol
: required The protocol to which model changes should be persisted. - BinderOptions
options
: optional- *
query
: optional A query, if necessary. This is available asbinder.query
in any Change Pipeline functions, but is otherwise only used by some protocols. - String
type
: optional Should be one of constants available inbinderTypes
service. This is useful to help protocols know how to analyze changes, but should be used as a best practice to take advantage of future enhancements to theOmniBinder
module. - String
key
: optional If the model is a collection of objects, the key helps methods in the Change Pipeline by confirming which property in the collection should be unique.
- *
Returns: Binder
A convenience factory to generate a well-formed ArrayChange object.
The factory takes the following arguments:
- Integer
addedCount
: required - Array
removed
: required - Integer
index
: required
Returns: ArrayChange change
Re-constructs the previous version of an object, based on information from an ObjectChange.
The factory takes the following arguments:
- ObjectChange
change
: required
Returns: Object oldObject
Not Yet Implemented
-
observeObjectInCollection
Observe a single object in a collection.When Object.observe notifies that this object has changed, the callback will be called with the proper context, and will prepare an Array.observe-like changeset instead of the Object.observe style of changes.
The assumption is that when observing a collection, the preferred format of changes will operations that can be applied to a collection to easily keep multiple copies of a collection in sync.
A member outside the scope of this service would need to compare the new item with the removed item to determine if the change was actually an update to an object, rather than a removal/addition that is typically represented by an Array.observe change set. For example, the collection has a unique key constraint, the values of that key could be compared in the removed and added objects.
Arguments:
- Binder
context
: required - Array
collection
: required - Object
object
: required - Function
callback
: required
- Binder
-
observeCollection
Observe an array and its child objects, then notify callback on any change.Arguments:
- Binder
context
The context with which to call the callback. - Array
collection
The collection to be observed. - Function
callback
The callback to call on an array change.
- Binder
A static dictionary of model types which can be optionally be
added to the options object passed into obBinder
in order to provide an opportunity to reduce ambiguity in
Change Pipeline methods,
and potentially the protocol.
This value can help OmniBinder know how to create or update
models in ambiguous circumstances.
The service currently contains the following constants:
- String
COLLECTION
= "collection" For lists of any type of data. - String
OBJECT
= "object" For plain old objects. - String
BOOLEAN
= "boolean" - String
STRING
= "string" - String
NUMBER
= "number" - String
BINARY
= "binary" For binary data such as an image, video, audio clip. - String
BINARY_STREAM
= "binaryStream" For streaming binary data such as video chat or audio call.
...
var binder = obBinder($scope, 'myModel', {
type: binderTypes.COLLECTION
});
A protocol is the guts of the OmniBinder
module,
and manages the low-level synchronization of a local model to a remote data store.
A protocol only needs to expose these methods to be used by obBinder
instances.
- processChanges (Binder binder, Delta delta)
Takes a delta with an array of
Object.observe
orArray.observe
type changes, and applies them to the protocol's version of the model. - subscribe (Binder binder)
This method is called as soon as a binder object is created
from obBinder, in order to get an initial value for the model and to
automatically update the model upon further changes in the
persistence layer.
The protocol should call
binder.onProtocolChange(Delta delta)
containing an array of properly-formatted changes to be applied to the model. - unsubscribe(Binder binder)
Called when a bound scope is destroyed or when
binder.unbind()
is called.
Protocols must implement this interface when passed into the obBinder
factory.
Protocols may require a configuration step prior to being passed in,
but obBinder is not concerned with how a protocol prepares itself.
For example, both of the following examples are okay.
Example 1: Generate protocol from a factory
myApp.factory('myProtocolFactory', function () {
return function (url) {
return {
processChanges: function (binder, delta) {
// Evaluate changes and sync at the provided URL
},
subscribe: function (binder, callback) {
// Subscribe to protocol at the provided URL
}
}
}
});
myApp.controller('UserCtrl', function ($scope, obBinder, myProtocolFactory) {
$scope.users = [];
var protocol = myProtocolFactory('http://path.to.api');
var binder = obBinder($scope, 'users', protocol);
});
Example 2: Protocol is a ready-to-go service
myApp.service('myProtocolService', function () {
this.subscribe = function (binder, callback) {
if (!binder.query.url) throw new Error('Binder query must contain a url');
// Subscribe to provided url
};
});
myApp.controller('UserCtrl', function ($scope, obBinder, myProtocolService) {
$scope.users = [];
var binder = obBinder($scope, 'users', myProtocolService, {
query: {
url: 'http://path.to.api'
}
});
});
Protocols may make use of the query
object attached to a binder
to ensure that the data is being persisted properly.
Queries may contain a URL path to a resource on a server,
an id of a particular object,
or filters to restrict changes to certain items.
obBinder
has no policy on what type of object a query is,
or what properties it contains.
The extent of the policy is that if different models should be treated
differently by a protocol, the place to store the instructions is on binder.query
.
The protocol interface is still being actively developed, and will change.
Created by the obBinder
factory.
- onProtocolChange
- onModelChange
- val
- unBind
- Scope
scope
- String
model
- *
query
- BinderType
type
- Protocol
protocol
A new delta
object is created each time a change is registered from a local model or protocol.
The delta
is passed to every method in the Change Pipeline. The only required property of a delta is changes
, which is an array of Object.observe
or Array.observe
changes to be processed by a model or protocol.
- Array<ArrayChange, ObjectChange>
changes
Based on changes generated by observe-js,
which is based on natively-implemented Array.observe
API.
These change objects are used to syndicate changes on
models between different sources in as simple a format as possible.
- Integer
index
- Array
removed
- Integer
addedCount
Similar to ArrayChange, but focused on applying changes to plain old JavaScript objects.
- String
name
- Object
object
- *
oldValue
- String
type
An options object that can be passed as the final argument to
the obBinder
factory to help facilitate model synchronization.
- BinderType
type
- String
key
- *
query