reactive-property
Advanced tools
Comparing version 0.5.0 to 0.6.0
25
index.js
@@ -17,16 +17,27 @@ // UMD boilerplate (from Rollup) | ||
return function ReactiveProperty(value, context){ | ||
var listeners, i; | ||
if(arguments.length > 2) { throw Error(errors.tooManyArgsConstructor); } | ||
var listeners; | ||
if(arguments.length > 2) { | ||
throw Error(errors.tooManyArgsConstructor); | ||
} | ||
function property(newValue){ | ||
if(arguments.length > 1) { throw Error(errors.tooManyArgsSetter); } | ||
if(arguments.length > 1) { | ||
throw Error(errors.tooManyArgsSetter); | ||
} | ||
if(arguments.length === 1){ | ||
value = newValue; | ||
if(listeners){ | ||
for(i = 0; i < listeners.length; i++){ listeners[i](value); } | ||
for(var i = 0; i < listeners.length; i++){ | ||
listeners[i].call(context, value); | ||
} | ||
} | ||
return context; | ||
} else { | ||
return value; | ||
} | ||
return value; | ||
} | ||
@@ -50,3 +61,3 @@ | ||
if(typeof(value) !== "undefined"){ | ||
if(typeof(value) !== "undefined" && value !== null){ | ||
listener.call(context, value); | ||
@@ -53,0 +64,0 @@ } |
{ | ||
"name": "reactive-property", | ||
"version": "0.5.0", | ||
"version": "0.6.0", | ||
"description": "A small library for getter-setter functions that react to changes.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
154
README.md
@@ -9,3 +9,3 @@ # reactive-property | ||
## Quick Start | ||
## Usage | ||
@@ -22,2 +22,14 @@ Install the library by running this command. | ||
If you're not using NPM, you can require the script in your HTML like this. | ||
```html | ||
<script src="//curran.github.io/reactive-property/reactive-property-v0.5.0.js"></script> | ||
``` | ||
Or, you can use the minified version (1.5K). | ||
```html | ||
<script src="//curran.github.io/reactive-property/reactive-property-v0.5.0.min.js"></script> | ||
``` | ||
Create your first property. | ||
@@ -54,5 +66,6 @@ | ||
a.off(listener); | ||
a(5); // The listener is NOT called. | ||
``` | ||
Set up method chaining for setters using a context object. | ||
Set up method chaining by using a context object. | ||
@@ -66,137 +79,26 @@ ```javascript | ||
## Example Code | ||
You can access the context object as `this` in listeners. | ||
Here's some example code from the [tests](https://github.com/curran/reactiveProperty/blob/master/test.js) that demonstrates the functionality of this library. | ||
```javascript | ||
var ReactiveProperty = require("reactive-property"); | ||
var assert = require("assert"); | ||
describe("Getter-setters", function() { | ||
it("Should construct a property with a default value and get the value.", function () { | ||
var a = ReactiveProperty(5); | ||
assert.equal(a(), 5); | ||
}); | ||
it("Should set and get and the value.", function () { | ||
var a = ReactiveProperty(); | ||
a(10); | ||
assert.equal(a(), 10); | ||
}); | ||
it("Should set the value, overriding the default value.", function () { | ||
var a = ReactiveProperty(5); | ||
a(10); | ||
assert.equal(a(), 10); | ||
}); | ||
my.x.on(function(value){ | ||
console.log(this === my); // Prints "true" | ||
}); | ||
``` | ||
In addition to setting and getting values, you can also listen for changes using the `on` function. | ||
For more detailed example code, have a look at the [tests](https://github.com/curran/reactiveProperty/blob/master/test.js).. | ||
```javascript | ||
it("Should react to changes.", function (done) { | ||
var a = ReactiveProperty(); | ||
a.on(function (){ | ||
assert.equal(a(), 10); | ||
done(); | ||
}); | ||
a(10); | ||
}); | ||
## Background | ||
it("Should react to the default value.", function (done) { | ||
var a = ReactiveProperty(5); | ||
a.on(function (){ | ||
assert.equal(a(), 5); | ||
done(); | ||
}); | ||
}); | ||
After many attempts at building "frameworks" for data visualization ([ModelJS](https://github.com/curran/model), [Chiasm](https://github.com/chiasm-project/chiasm)), I have learned that abstractions come at a cost. Much to my dismay, I found that when I wanted to apply Chiasm to a particular project, the abstractions had too much surface area and stood in the way of customization. I found myself starting again from raw D3 examples to get projects done, and noticed that as a project grows in complexity organically, the most common need is to *listen for changes in state*. | ||
it("Should not react to no value.", function () { | ||
var a = ReactiveProperty(); | ||
var numInvocations = 0; | ||
a.on(function (){ numInvocations++; }); | ||
assert.equal(numInvocations, 0); | ||
}); | ||
**This library is my attempt to create a "micro-framework" that eliminates the getter-setter boilerplate code and provides the ability to listen for changes in state.** It is intentionally minimal, and no other features are provided. This is to minimize the surface area of this library, and make it appealing for others to adopt as a utility in D3-based projects. | ||
it("Should react synchronously.", function () { | ||
var a = ReactiveProperty(); | ||
var numInvocations = 0; | ||
a.on(function (){ numInvocations++; }); | ||
assert.equal(numInvocations, 0); | ||
a(10); | ||
assert.equal(numInvocations, 1); | ||
a(15); | ||
assert.equal(numInvocations, 2); | ||
}); | ||
This library is "complete" and fully functional as-is. Aside from bugs or edge cases that come up, no new features will be added to this library. This library is designed to be the foundation of larger systems, and additional functionality should arise by composing this library with other code. | ||
it("Should pass the value to the listener as an argument.", function (done) { | ||
var a = ReactiveProperty(); | ||
a.on(function (value){ | ||
assert.equal(value, 10); | ||
done(); | ||
}); | ||
a(10); | ||
}); | ||
``` | ||
## Contributing | ||
Here's how you can unregister a listener. | ||
* If you think this project is cool, please give it a star! | ||
* If you end up using this in an example on bl.ocks.org, please let me know by creating a GitHub issue, we can link to your example in this README. | ||
* Feel free to open GitHub issues if you have any questions, comments or suggestions. | ||
```javascript | ||
it("Should stop reacting to changes.", function () { | ||
var a = ReactiveProperty(); | ||
var numInvocations = 0; | ||
var listener = a.on(function (){ numInvocations++; }); | ||
a(10); | ||
assert.equal(numInvocations, 1); | ||
a.off(listener); | ||
a(15); | ||
assert.equal(numInvocations, 1); | ||
}); | ||
``` | ||
You can also assign a context object to properties. This gets returned from setters to enable method chaining, and also is passed to listeners as `this`. | ||
```javascript | ||
it("Should accept a context object and return it from setters (method chaining).", function (){ | ||
var context = {}; | ||
context.a = ReactiveProperty(5, context); | ||
context.b = ReactiveProperty(10, context); | ||
assert.equal(context.a(), 5); | ||
assert.equal(context.b(), 10); | ||
context | ||
.a(50) | ||
.b(100); | ||
assert.equal(context.a(), 50); | ||
assert.equal(context.b(), 100); | ||
}); | ||
it("Should pass the context object as 'this' in listeners.", function (done){ | ||
var context = {}; | ||
context.a = ReactiveProperty(5, context); | ||
context.b = ReactiveProperty(10, context); | ||
context.a.on(function (value){ | ||
assert.equal(this, context); | ||
done(); | ||
}); | ||
}); | ||
``` | ||
## Background | ||
After many attempts at building "frameworks" for data visualization ([ModelJS](https://github.com/curran/model), [Chiasm](https://github.com/chiasm-project/chiasm)), I have learned that abstractions come at a cost proportional to their surface area. Much to my dismay, I found that when I wanted to apply Chiasm to a particular project, the abstractions stood in the way of customization and I found myself starting again from raw D3 examples to get projects done. After a project grows in complexity, the most common need is to *listen for changes in state*. | ||
This library is my attempt to create a "micro-framework" that fits will with interactive data visualizations, particularly using D3, and provides the ability to listen for changes in state. It is intentionally minimal, and *no other features* are provided. This is to minimize the surface area of this library, and make it appealing for others to adopt as a utility in D3-based projects. | ||
This library is "complete" and fully functional as-is. Aside from bugs or edge cases that come up, no new features will be added to this library. This library is designed to be the foundation of larger systems, and additional functionality should arise by composing this library with other code. | ||
I hope you enjoy and benefit from this project! Feel free to open GitHub issues if you have any questions, comments or suggestions. | ||
I hope you enjoy and benefit from this project! |
17
test.js
@@ -83,2 +83,9 @@ // Unit tests for reactive-property. | ||
it("Should not react to null.", function () { | ||
var a = ReactiveProperty(null); | ||
var numInvocations = 0; | ||
a.on(function (){ numInvocations++; }); | ||
assert.equal(numInvocations, 0); | ||
}); | ||
it("Should react synchronously.", function () { | ||
@@ -116,12 +123,14 @@ var a = ReactiveProperty(); | ||
it("Should pass the context object as 'this' in listeners.", function (done){ | ||
var context = {}; | ||
context.a = ReactiveProperty(5, context); | ||
context.b = ReactiveProperty(10, context); | ||
context.a.on(function (value){ | ||
assert.equal(this, context); | ||
done(); | ||
if(value === 5){ | ||
context.a(10); | ||
} else { | ||
done(); | ||
} | ||
}); | ||
}); | ||
}); | ||
@@ -128,0 +137,0 @@ |
237
13377
101