Skip to content

Commit

Permalink
[BUGFIX beta] Fixes emberjs#14298 rendering aliased paths
Browse files Browse the repository at this point in the history
When dirtying an object, other objects with aliases
that path through this object should dirty as well.
  • Loading branch information
krisselden authored and webark committed Oct 6, 2016
1 parent bddb181 commit babe4c8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 26 deletions.
39 changes: 39 additions & 0 deletions packages/ember-glimmer/tests/integration/content-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,45 @@ class DynamicContentTest extends RenderingTest {
this.assertContent('hello');
this.assertInvariants();
}

['@test it can render a readOnly property of a path']() {
let Messenger = EmberObject.extend({
message: computed.readOnly('a.b.c')
});

let messenger = Messenger.create({
a: {
b: {
c: 'hello'
}
}
});

this.renderPath('messenger.message', { messenger });

this.assertContent('hello');

this.assertStableRerender();

this.runTask(() => set(messenger, 'a.b.c', 'hi'));

this.assertContent('hi');
this.assertInvariants();

this.runTask(() => set(this.context, 'messenger.a.b', {
c: 'goodbye'
}));

this.assertContent('goodbye');
this.assertInvariants();

this.runTask(() => set(this.context, 'messenger', {
message: 'hello'
}));

this.assertContent('hello');
this.assertInvariants();
}
}

const EMPTY = {};
Expand Down
16 changes: 2 additions & 14 deletions packages/ember-metal/lib/alias.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,15 @@ AliasedProperty.prototype.set = function AliasedProperty_set(obj, keyName, value
return set(obj, this.altKey, value);
};

AliasedProperty.prototype.willWatch = function(obj, keyName) {
addDependentKeys(this, obj, keyName, meta(obj));
};

AliasedProperty.prototype.didUnwatch = function(obj, keyName) {
removeDependentKeys(this, obj, keyName, meta(obj));
};

AliasedProperty.prototype.setup = function(obj, keyName) {
assert(`Setting alias '${keyName}' on self`, this.altKey !== keyName);
let m = meta(obj);
if (m.peekWatching(keyName)) {
addDependentKeys(this, obj, keyName, m);
}
addDependentKeys(this, obj, keyName, m);
};

AliasedProperty.prototype.teardown = function(obj, keyName) {
let m = meta(obj);
if (m.peekWatching(keyName)) {
removeDependentKeys(this, obj, keyName, m);
}
removeDependentKeys(this, obj, keyName, m);
};

AliasedProperty.prototype.readOnly = function() {
Expand Down
33 changes: 21 additions & 12 deletions packages/ember-metal/tests/alias_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { set } from '../property_set';
import { meta } from '../meta';
import { isWatching } from '../watching';
import { addObserver, removeObserver } from '../observer';
import { tagFor } from '../tags';

let obj, count;

Expand Down Expand Up @@ -33,15 +34,6 @@ QUnit.test('should proxy set to alt key', function() {
equal(get(obj, 'foo.faz'), 'BAR');
});

QUnit.test('basic lifecycle', function() {
defineProperty(obj, 'bar', alias('foo.faz'));
let m = meta(obj);
addObserver(obj, 'bar', incrementCount);
equal(m.peekDeps('foo.faz', 'bar'), 1);
removeObserver(obj, 'bar', incrementCount);
equal(m.peekDeps('foo.faz', 'bar'), 0);
});

QUnit.test('old dependent keys should not trigger property changes', function() {
let obj1 = Object.create(null);
defineProperty(obj1, 'foo', null, null);
Expand All @@ -59,8 +51,13 @@ QUnit.test('old dependent keys should not trigger property changes', function()
equal(count, 1);
});

QUnit.test('overridden dependent keys should not trigger property changes', function() {
QUnit.test(`inheriting an observer of the alias from the prototype then
redefining the alias on the instance to another property dependent on same key
does not call the observer twice`, function() {
let obj1 = Object.create(null);

meta(obj1).proto = obj1;

defineProperty(obj1, 'foo', null, null);
defineProperty(obj1, 'bar', alias('foo'));
defineProperty(obj1, 'baz', alias('foo'));
Expand All @@ -78,22 +75,34 @@ QUnit.test('overridden dependent keys should not trigger property changes', func
equal(count, 1);
});

QUnit.test('begins watching alt key as soon as alias is watched', function() {
QUnit.test('an observer of the alias works if added after defining the alias', function() {
defineProperty(obj, 'bar', alias('foo.faz'));
addObserver(obj, 'bar', incrementCount);
ok(isWatching(obj, 'foo.faz'));
set(obj, 'foo.faz', 'BAR');
equal(count, 1);
});

QUnit.test('immediately sets up dependencies if already being watched', function() {
QUnit.test('an observer of the alias works if added before defining the alias', function() {
addObserver(obj, 'bar', incrementCount);
defineProperty(obj, 'bar', alias('foo.faz'));
ok(isWatching(obj, 'foo.faz'));
set(obj, 'foo.faz', 'BAR');
equal(count, 1);
});

QUnit.test('object with alias is dirtied if interior object of alias is set', function () {
defineProperty(obj, 'bar', alias('foo.faz'));
assertDirty(obj, () => set(obj, 'foo.faz', 'BAR'), 'setting the aliased key should dirty the object');
});

QUnit.test('setting alias on self should fail assertion', function() {
expectAssertion(() => defineProperty(obj, 'bar', alias('bar')), 'Setting alias \'bar\' on self');
});

function assertDirty(obj, callback, label) {
let tag = tagFor(obj);
let tagValue = tag.value();
callback();
ok(!tag.validate(tagValue), label);
}

0 comments on commit babe4c8

Please sign in to comment.