/glue.js

Implements Object.watch for javascript objects

Primary LanguageJavaScriptMIT LicenseMIT

Overview

glue.js is a key-value observing library for Javascript. glue.js supports both assigned and computed properties, nested in an abitrarily deep object graph.

Basic Use

Given the following object:

var targetObject = { v1: '' };

The target object can be passed to the Glue constructor to create an instance of Glue.

var glue = new Glue(targetObject);

glue.addObserver("*", function() {
  console.log('Target object changed.');
});

glue.set('v1', 'a value'); // 'Target object changed.'

In the example above, "Target object changed." is logged on the console when the value of v1 changed by the set operator.

For more examples, please see the specs directory.

###Keys Keys are a core concept in Glue, for both observers and operations (ie: set).

var target = {
  name: "Felix",
  contact: {
    phone: "555-555-5555",
    email: "felix@edgecase.com"
  }
}

var glue = new Glue(target);
glue.addObserver("", function(message) {
  // callback will be triggered on any modification
  // ex: glue.set("name", "foo");
  // ex: glue.set("contact.email", "foo@edgecase.com");
});
glue.addObserver("contact", function(message) {
  // callback will be triggered on any modification to the contact property
  // ex: glue.set("contact", {});
  // ex: glue.set("contact.email", "foo@edgecase.com");

  // callback will not be triggered on modification of other properties
  // ex: glue.set("name", "foo");
});
glue.addObserver("contact.email", function(message) {
  // callback will be triggered on any modification to the email property of the contact object.
  // ex: glue.set("contact.email", "foo@edgecase.com");

  // callback will not be triggered on modification of other properties
  // ex: glue.set("contact.phone", "123-456-7890");
});

####Array Specific Keys Assume the following target

var target1 = [1, 2, 3, 4, 5];
var glue = new Glue(target1);
glue.addObserver('[2]', function(message) {
  // callback is executed only when a change occurs to the element at index 2 of the array.
});
glue.addObserver('[]', function(message) {
  // callback is executed for every element that changes in the array.
});

####Additional Examples

var target = { v1: { arr1: [ { v2: { arr2: [ 'something' ] } } ] } };
var glue = new Glue(target);

The following keys can be used:

'v1.arr1[0].v2.arr2[0]',
'v1.arr1[0].v2.arr2[]',
'v1.arr1[0].v2.arr2',
'v1.arr1[0].v2',
'v1.arr1[0]',
'v1.arr1[]',
'v1.arr1',
'v1',
'*'

Note that generics [] can only be at the end of the key. Example: 'v1.arr1[0].arr2[]' is legal, but 'v1.arr1[].arr2[]' is not

Core methods

##Constructor

new Glue(targetObject);

targetObject: the object that will be observed by Glue.

##addObserver

glue.addObserver([key(s):operation(s)], [context], callback);

key(s) (optional): specifies the key or index that will be observed by the observer.

operation(s) (optional): restricts the callback's execution for a particular operation. (push, pop, etc.)

context (optional): the context which the callback is to be executed. By default, callbacks are executed in the context of the target object.

callback: the function to be executed when the observer is notified. Callbacks are passed a message parameter that contains information about what changed on the key being listened to.

###Examples

Setting a listen for a key:

glue.addObserver('v1', callback);

Setting a observer for multiple keys:

glue.addObserver('v1, v2', callback);

Setting a observer for a specific operation:

glue.addObserver('v1:set', function(message) {
  // callback
});

Setting a observer for multiple operations:

glue.addObserver('v1:set, v2:push, :insert', function(message) {
  // callback
});

###Context By default all callbacks are executed in the context of the target object, but can be specified by following:

var myContext = { a: ''};

glue.addObserver(myContext, function(message) {
  // "this" in side the callback is myContext
  this.a = 'context';
});

When the callback above is executed, myContext will have the value { a: 'context' }

The context can be used in conjunction with keys and operations as follows:

glue.addObserver('v1:set', context, function(message) {
  // callback
});

The example below demonstrates context.

var context = { myWord: 'Oh my' },
    target = { v1: '' },
    glue = new Glue(target);

glue.addObserver(context, function(message) {
  this.myWord = message.value;
});

glue.set('v1', 'Hello');

console.log(context); // { myWord: 'Hello' }

###Messages A message object is passed to the observer callback function.

####Basic Messages

var messages = [],
    target1 = { foo: "bar" },
    glue = new Glue(target1);


glue.addObserver('*', function(msg) {
  console.log(message);
});

glue.set('foo', 'baz');

// Output
// {
//   value: "baz",
//   operation: 'set'
// }

####Array Specific messages

Messages content depend on the type of key is assigned to the observer.

var message,
    target1 = { arr: [1, 2, 3, 4, 5] },
    glue = new Glue(target1);

glue.addObserver('arr[2]', function(msg) {
  message = msg;
});

glue.set('arr[2]', 9);

console.log(message); // [{ value: 9, operation: 'set' }]

On the other hand:

var message,
  target1 = { arr: [1, 2, 3, 4, 5] },
  glue = new Glue(target1);


glue.addObserver('arr[]', function(msg) {
  message = msg;
});

glue.set('arr[2]', 9);

console.log(message); // { value: 9, index: 2, operation: 'set' }

And directly to the target:

var messages = [],
    target1 = { arr: [1, 2, 3, 4, 5] },
    glue = new Glue(target1);


glue.addObserver('*', function(msg) {
  messages.push(msg);
});

glue.set('arr[2]', 9);

console.log(message);
// {
//   value: { arr: [ 1, 2, 9, 4, 5 ] },
//   operation: 'set'
// }
var messages = [],
    target1 = [1, 2, 3, 4, 5],
    glue = new Glue(target1);

glue.addObserver('[]', function(msg) {
  messages.push(msg);
});

glue.filter(function(num) {
  return num % 2 === 0;
});

console.log(messages)

// ------------------------------- messages ---------------------------------
// [
//   { value: undefined, index: 4, operation: 'filter' },
//   { value: undefined, index: 3, operation: 'filter' },
//   { value: undefined, index: 2, operation: 'filter' },
//   { value: 4, index: 1, operation: 'filter' },
//   { value: 2, index: 0, operation: 'filter' }
// ];
// --------------------------------------------------------------------------

##removeObserver

glue.addObserver([key(s):operation(s))], [context]);

key(s) (optional): the key to be removed

operation(s) (optional): the operation to be removed

context (optional): the context to be removed

Example

glue.removeObserver('key');
glue.removeObserver('key1, key2');
glue.removeObserver('key1, key2:operation');

glue.removeObserver(':operation');
glue.removeObserver(':operation1, operation2');

glue.removeObserver('key:operation');
glue.removeObserver('key:operation, operation2');
glue.removeObserver('key1, key2:operation, operation2');

glue.removeObserver('key', context);
glue.removeObserver(':operation', context);
glue.removeObserver('key1, key2:operation', context);
glue.removeObserver('key:operation1, operation2', context);
glue.removeObserver('key1, key2:operation, operation2', context);

##set

glue.set(key, value);

Example:

var glue = new Glue({ v1: '' });
glue.set('v1', 'something');

console.log(glue.target); // { 'v1', 'something' }

##remove

glue.remove(key);

Example:

var glue = new Glue({ v1: 'something' });
glue.remove('v1'); // 'something'

console.log(glue.target); // {}

##push

glue.push([key], value);

Example:

var glue = new Glue([1,2,3]);
glue.push(4)

console.log(glue.target); // [1,2,3,4]

##pop

glue.pop([key]);

Example:

var glue = new Glue([1,2,3]);
glue.pop() // 4

console.log(glue.target); // [1,2,3]

##insert

glue.insert([key], index, value);

Example:

var glue = new Glue([1,2,3]);
glue.insert(1, 9);

console.log(glue.target); // [1, 9, 2, 3]

##filter

glue.filter([key], iterator);

Example:

var glue = new Glue([1,2,3,4,5]);
glue.filter(function(num) {
  return num % 2 === 0;
}); // [2,4]

console.log(glue.target); // [2, 4]

###sortBy

glue.sortBy([key], iterator);

Example

var glue = new Glue(_.shuffle(['1elem', '2elem', '3elem', '4elem' ,'5elem']));

glue.sortBy(function(elem) { return parseInt(elem) });
console.log(glue.target); //['1elem', '2elem', '3elem', '4elem' ,'5elem']

##swap

glue.swap(key1, key2);

Example

var glue = new Glue({ v1: '', v2: { v3: 'hello' }});

glue.swap('v1', 'v2.v3');
console.log(glue.target); //{ v1: 'hello', v2: { v3: '' }}