Hey Folks, I’m trying to wrap my brain around some of the autotracking changes in Octane and having a hard time. Does autotracking work on a Set?
I want to calculate the height of a list of elements and I figured a Set would make the unique tracking easy. Take a look at the code below. I have a Set of dom elements, which is tracked. The height() method isn’t being called again when the elements changes.
@tracked elements = new Set();
get height() {
if (this.elements.size === 0) {
return 'auto';
}
let height = [...this.elements].reduce((sum, el) => sum + el.offsetHeight);
return `${height}px`;
}
@action
addEl(el) {
this.elements.add(el);
}
@action
removeEl(el) {
this.elements.delete(el);
}
Then I’m referencing height in a template:
<div
style="flex-basis: {{this.height}}"
>
...
This is my first attempt at using a Set as well, so it’s possible I’m heading down the wrong path before the autotracking confusion. I’ve tried this with elements as an array and height is still not called.
Out of the box, no, it doesn’t: because you’re tracking the Set instance, not its internals. However, you can use the tracked-built-ins addon, which supplies auto-tracked versions of Map, WeakMap, Set, and WeakSet.
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from 'tracked-built-ins'; // NOTE THE IMPORT!
export default DemoIt extends Component {
@tracked elements = new Set();
get height() {
if (this.elements.size === 0) {
return 'auto';
}
let height = [...this.elements].reduce((sum, el) => sum + el.offsetHeight);
return `${height}px`;
}
@action
addEl(el) {
this.elements.add(el);
}
@action
removeEl(el) {
this.elements.delete(el);
}
}
As Set.add() returns the set instance this would also work and may look less confusing:
this.elements = this.elements.add(el);
But this does not work for Set.delete(), which returns true if the item was in the set and false otherwise.
I think an notifyChange utility function is the best solution for know. It’s readable but does not come with limitations and drawbacks of tracked-built-ins.
I’m looking forward to Tracked Maps and Sets RfC, which provides best long-term solution in my opinion.
Unfortunately, this wouldn’t help with getting specific items from the Set (or a Map) in a template. It would not notify that the item within the collection had been changed. In fact, that’s what the tracked-built-in’s library and the RFC you linked account for.
The difference, if I recall correctly, is that get, which template invocations use when resolving their values, is aware of properties (as used in that example) but doesn’t know how to get the values from Set or Map. It can be “taught” to, and that’s part of what the RFC for native tracked Map and Set proposes, but today it doesn’t. (@pzuraq can correct me if I’ve got that wrong in some way!)