Skip to content

Commit

Permalink
Allow properties on functions to be watchable/streamable
Browse files Browse the repository at this point in the history
Allows things like {{foo.bar}} to bind properly
when foo is a function

Use cases: the function form of
emberjs/rfcs#2
  • Loading branch information
machty committed Jul 14, 2015
1 parent f59d716 commit adbb301
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 6 deletions.
15 changes: 10 additions & 5 deletions packages/ember-metal/lib/chains.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ function firstKey(path) {
return path.match(FIRST_KEY)[0];
}

function isObject(obj) {
return obj && (typeof obj === 'object');
function isWatchable(obj) {
if (!obj) {
return;
}

let type = typeof obj;
return type === 'object' || type === 'function';
}

function isVolatile(obj) {
return !(isObject(obj) && obj.isDescriptor && obj._cacheable);
return !(isWatchable(obj) && obj.isDescriptor && obj._cacheable);
}

function Chains() { }
Expand All @@ -42,7 +47,7 @@ export function flushPendingChains() {
}

function addChainWatcher(obj, keyName, node) {
if (!isObject(obj)) {
if (!isWatchable(obj)) {
return;
}

Expand All @@ -63,7 +68,7 @@ function addChainWatcher(obj, keyName, node) {
}

function removeChainWatcher(obj, keyName, node) {
if (!isObject(obj)) {
if (!isWatchable(obj)) {
return;
}

Expand Down
3 changes: 2 additions & 1 deletion packages/ember-metal/lib/streams/key-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ merge(KeyStream.prototype, {
if (object !== this.observedObject) {
this._clearObservedObject();

if (object && typeof object === 'object') {
var type = typeof object;
if (object && (type === 'object' || type === 'function')) {
addObserver(object, this.key, this, this.notify);
this.observedObject = object;
}
Expand Down
17 changes: 17 additions & 0 deletions packages/ember-metal/tests/streams/key-stream-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ QUnit.test('is notified when the observed object\'s property is mutated', functi
equal(nameStream.value(), 'wycats', 'Stream value is correct');
});

QUnit.test('is notified when properties on functions are mutated', function() {
var fn = function() {};
fn.foo = 'mmun';
source = new Stream(function() { return fn; });

var nameStream = source.get('foo');
nameStream.subscribe(incrementCount);

equal(count, 0, 'Subscribers called correct number of times');
equal(nameStream.value(), 'mmun', 'Stream value is correct');

set(fn, 'foo', 'wycats');

equal(count, 1, 'Subscribers called correct number of times');
equal(nameStream.value(), 'wycats', 'Stream value is correct');
});

QUnit.test('is notified when the source stream\'s value changes to a new object', function() {
var nameStream = source.get('name');
nameStream.subscribe(incrementCount);
Expand Down
19 changes: 19 additions & 0 deletions packages/ember-metal/tests/watching/watch_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,22 @@ testBoth('watching "length" property on an array', function(get, set) {
equal(get(arr, 'length'), 10, 'should get new value');
equal(arr.length, 10, 'property should be accessible on arr');
});

testBoth('watching properties on a function', function(get, set) {
var obj = {
foo: function() {}
};
addListeners(obj, 'foo.baz');

watch(obj, 'foo.baz');
equal(get(obj, 'foo.baz'), undefined, 'should have original prop');

set(obj, 'foo.baz', 'bar');
equal(willCount, 1, 'should have invoked willCount');
equal(didCount, 1, 'should have invoked didCount');

equal(get(obj, 'foo.baz'), 'bar', 'should get new value');
equal(obj.foo.baz, 'bar', 'property should be accessible on obj');
});


0 comments on commit adbb301

Please sign in to comment.