Skip to content

Commit bc012f7

Browse files
committed
Run did-update callback in an untracked frame
Modifier capabillities in 3.22, requires all arguments to be consumed, to be tracked. This meant `disableAutoTracking` had to be set to `false` for the modifier to work with 3.22 capabillities. This had the sideeffect that any other consumed tags ended up being tracked. Meaning the `did-update` callback was invoked whenever those tags changed.
1 parent 9ca07e8 commit bc012f7

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

addon/modifiers/did-update.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { setModifierManager, capabilities } from '@ember/modifier';
22
import { gte } from 'ember-compatibility-helpers';
3+
import { untrack } from '@glimmer/validator';
34

45
/**
56
The `{{did-update}}` element modifier is activated when any of its arguments
@@ -80,17 +81,20 @@ export default setModifierManager(
8081
},
8182

8283
updateModifier({ element }, args) {
84+
let [fn, ...positional] = args.positional;
85+
8386
if (gte('3.22.0')) {
8487
// Consume individual properties to entangle tracking.
8588
// https://github.com/emberjs/ember.js/issues/19277
8689
// https://github.com/ember-modifier/ember-modifier/pull/63#issuecomment-815908201
8790
args.positional.forEach(() => {});
8891
args.named && Object.values(args.named);
92+
untrack(() => {
93+
fn(element, positional, args.named);
94+
});
95+
} else {
96+
fn(element, positional, args.named);
8997
}
90-
91-
let [fn, ...positional] = args.positional;
92-
93-
fn(element, positional, args.named);
9498
},
9599

96100
destroyModifier() {},

tests/integration/modifiers/did-update-test.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { module, test } from 'qunit';
2+
import { tracked } from '@glimmer/tracking';
23
import { setupRenderingTest } from 'ember-qunit';
3-
import { render } from '@ember/test-helpers';
4+
import { render, settled } from '@ember/test-helpers';
45
import hbs from 'htmlbars-inline-precompile';
56

67
module('Integration | Modifier | did-update', function (hooks) {
@@ -24,4 +25,26 @@ module('Integration | Modifier | did-update', function (hooks) {
2425

2526
this.set('boundValue', 'update');
2627
});
28+
29+
test('it consumes tracked properties without re-invoking', async function (assert) {
30+
class Context {
31+
@tracked boundValue = 'initial';
32+
@tracked secondaryValue = 'initial';
33+
}
34+
35+
assert.expect(1);
36+
this.context = new Context();
37+
38+
this.someMethod = () => {
39+
// This assertion works as an assurance that we render before `secondaryValue` changes,
40+
// and consumes its tag to ensure reading tracked properties won't re-trigger the modifier
41+
assert.equal(this.context.secondaryValue, 'initial');
42+
};
43+
44+
await render(hbs`<div {{did-update this.someMethod this.context.boundValue}}></div>`);
45+
46+
this.context.boundValue = 'update';
47+
await settled();
48+
this.context.secondaryValue = 'update';
49+
});
2750
});

0 commit comments

Comments
 (0)