From 028799fe4738504dbfd83cdc5983da6f160fdb0f Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 28 Feb 2019 12:53:22 -0500 Subject: [PATCH] [BUGFIX canary] Ensure @tracked setter triggers a revalidation. Prior to this change, setting a tracked property when there was on ambient runloop would never schedule a revalidation and would therefore never rerender. This change ensures that _any_ set of a `@tracked` property will enqueue a revalidation regardless if there is a current runloop or not. --- .../integration/components/tracked-test.js | 31 +++++++++++++++++++ packages/@ember/-internals/metal/lib/tags.ts | 2 +- .../@ember/-internals/metal/lib/tracked.ts | 4 +-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js b/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js index f9cd31f0bee..f9653c3644e 100644 --- a/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js +++ b/packages/@ember/-internals/glimmer/tests/integration/components/tracked-test.js @@ -32,6 +32,37 @@ if (EMBER_METAL_TRACKED_PROPERTIES) { this.assertText('1'); } + '@test tracked properties rerender when updated outside of a runloop'(assert) { + let done = assert.async(); + + let CountComponent = Component.extend({ + count: tracked({ value: 0 }), + + increment() { + setTimeout(() => { + this.count++; + }, 100); + }, + }); + + this.registerComponent('counter', { + ComponentClass: CountComponent, + template: '', + }); + + this.render(''); + + this.assertText('0'); + + // intentionally outside of a runTask + this.$('button').click(); + + setTimeout(() => { + this.assertText('1'); + done(); + }, 200); + } + '@test nested tracked properties rerender when updated'() { let Counter = EmberObject.extend({ count: tracked({ value: 0 }), diff --git a/packages/@ember/-internals/metal/lib/tags.ts b/packages/@ember/-internals/metal/lib/tags.ts index 61483a1a51d..845e2abc1b9 100644 --- a/packages/@ember/-internals/metal/lib/tags.ts +++ b/packages/@ember/-internals/metal/lib/tags.ts @@ -94,7 +94,7 @@ export function markObjectAsDirty(obj: object, propertyKey: string, meta: Meta): } } -function ensureRunloop(): void { +export function ensureRunloop(): void { if (hasViews()) { backburner.ensureInstance(); } diff --git a/packages/@ember/-internals/metal/lib/tracked.ts b/packages/@ember/-internals/metal/lib/tracked.ts index d8ef7e0cf4e..da11883e11a 100644 --- a/packages/@ember/-internals/metal/lib/tracked.ts +++ b/packages/@ember/-internals/metal/lib/tracked.ts @@ -4,7 +4,7 @@ import { DEBUG } from '@glimmer/env'; import { combine, CONSTANT_TAG, Tag } from '@glimmer/reference'; import { Decorator, ElementDescriptor } from './decorator'; import { setComputedDecorator } from './descriptor_map'; -import { dirty, tagFor, tagForProperty } from './tags'; +import { dirty, ensureRunloop, tagFor, tagForProperty } from './tags'; type Option = T | null; @@ -255,7 +255,7 @@ export interface Interceptors { [key: string]: boolean; } -let propertyDidChange = function(): void {}; +let propertyDidChange = ensureRunloop; export function setPropertyDidChange(cb: () => void): void { propertyDidChange = cb;