Skip to content

Commit

Permalink
[BUGFIX release] Ensure model can be observed by sync observers
Browse files Browse the repository at this point in the history
This is a compatibility change, otherwise sync observers
will not be able to watch the model property of controllers
at all. Also fixes the naming of the final flag to Observable#addObserver
and Observable#removeObserver
  • Loading branch information
Chris Garrett committed Oct 9, 2019
1 parent f786e42 commit 93cf8c7
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 9 deletions.
12 changes: 6 additions & 6 deletions packages/@ember/-internals/runtime/lib/mixins/observable.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,12 +362,12 @@ export default Mixin.create({
@param {String} key The key to observe
@param {Object} target The target object to invoke
@param {String|Function} method The method to invoke
@param {Boolean} async Whether the observer is async or not
@param {Boolean} sync Whether the observer is sync or not
@return {Observable}
@public
*/
addObserver(key, target, method, async) {
addObserver(this, key, target, method, async);
addObserver(key, target, method, sync) {
addObserver(this, key, target, method, sync);
return this;
},

Expand All @@ -380,12 +380,12 @@ export default Mixin.create({
@param {String} key The key to observe
@param {Object} target The target object to invoke
@param {String|Function} method The method to invoke
@param {Boolean} async Whether the observer is async or not
@param {Boolean} sync Whether the observer is async or not
@return {Observable}
@public
*/
removeObserver(key, target, method, async) {
removeObserver(this, key, target, method, async);
removeObserver(key, target, method, sync) {
removeObserver(this, key, target, method, sync);
return this;
},

Expand Down
15 changes: 13 additions & 2 deletions packages/@ember/controller/lib/controller_mixin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Mixin, tracked } from '@ember/-internals/metal';
import { Mixin, computed } from '@ember/-internals/metal';
import { ActionHandler } from '@ember/-internals/runtime';
import { symbol } from '@ember/-internals/utils';
import { EMBER_METAL_TRACKED_PROPERTIES } from '@ember/canary-features';

const MODEL = symbol('MODEL');

/**
@module ember
*/
Expand Down Expand Up @@ -43,5 +46,13 @@ export default Mixin.create(ActionHandler, {
@property model
@public
*/
model: EMBER_METAL_TRACKED_PROPERTIES ? tracked() : null,
model: computed({
get() {
return this[MODEL];
},

set(key, value) {
return (this[MODEL] = value);
},
}),
});
65 changes: 64 additions & 1 deletion packages/@ember/controller/tests/controller_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,70 @@ import Service, { inject as injectService } from '@ember/service';
import { Object as EmberObject } from '@ember/-internals/runtime';
import { Mixin, get } from '@ember/-internals/metal';
import { runDestroy, buildOwner } from 'internal-test-helpers';
import { moduleFor, AbstractTestCase } from 'internal-test-helpers';
import { moduleFor, ApplicationTestCase, AbstractTestCase, runTask } from 'internal-test-helpers';
import { action } from '@ember/object';

moduleFor(
'Controller model',
class extends ApplicationTestCase {
async '@test model is tracked'(assert) {
this.add(
'controller:index',
class extends Controller {
constructor() {
super(...arguments);
this.model = 0;
}

get derived() {
return this.model + 1;
}

@action
update() {
this.model++;
}
}
);

this.addTemplate('index', '<button {{on "click" this.update}}>{{this.derived}}</button>');

await this.visit('/');

this.assertText('1');

runTask(() => this.$('button').click());
this.assertText('2');
}

async '@test model can be observed with sync observers'(assert) {
let observerDidRun = false;

this.add(
'controller:index',
class extends Controller {
constructor() {
super(...arguments);
this.model = 0;

this.addObserver('model', this, () => (observerDidRun = true), true);
}

@action
update() {
this.model++;
}
}
);

this.addTemplate('index', '<button {{on "click" this.update}}>{{this.model}}</button>');

await this.visit('/');
runTask(() => this.$('button').click());
assert.equal(observerDidRun, true, 'observer ran');
}
}
);

moduleFor(
'Controller event handling',
Expand Down

0 comments on commit 93cf8c7

Please sign in to comment.