I am building my first Glimmmer component in Ember and I had something like this in my template:
<p>Some val: {{this.my_obj.some.deeply.nested.path.to.val}}</p>
I then made a corresponding .js
component file and thought I would try to remove the long path from the HTML.
My first attempt was to make a getter:
get val() {
return this.my_obj.some.deeply.nested.path.to.val;
}
With the template now:
<p>Some val: {{this.val}}</p>
That works initially and displays the starting value assigned to the val
variable, but it does not update when the underlying val
changes.
So I thought I would try marking the getter as tracked, but that made the output disapear:
@tracked val;
get val() {
return this.my_obj.some.deeply.nested.path.to.val;
}
I then tried this, but it's not valid syntax:
@tracked this.my_obj.some.deeply.nested.path.to.val;
So how should this be handled in a Glimmer component?
Surely the solution is not for the HTML to reference a deep path like this everytime the variable is referenced, however the new Ember docs, nice as they are, leave me none the wiser on this relatively simple/common case.
It's simple: whatever you change needs to be @tracked
. If you have {{this.my_obj.some.deeply.nested.path.to.val}}
in your hbs
or a getter that returns that does not make a difference.
But if you do this.my_obj.some.deeply.nested.path.to.val = "something"
and you want the value to update, you need to ensure that on this.my_obj.some.deeply.nested.path.to
val
is defined as tracked.
So this will not work:
@tracked data;
constructor() {
super(...arguments);
this.data = { foo: 1 };
}
@action test() {
this.data.foo = 2; // this will not correctly update
}
you need to ensure that foo
is @tracked
:
class DataWrapper {
@tracked foo;
}
...
@tracked data;
constructor() {
super(...arguments);
this.data = new DataWrapper();
this.data.foo = 1;
}
@action test() {
this.data.foo = 2; // this will now correctly update
}
Or you manually invalidate. So this will work:
@tracked data;
constructor() {
super(...arguments);
this.data = { foo: 1 };
}
@action test() {
this.data.foo = 2; // this will not update
this.data = this.data; // this ensures that everything that depends on `data` will correctly update. So `foo` will correctly update.
}
Also an important thing: @tracked
should never be defined on a getter. This will not work. It should directly be defined where you want to change something that should trigger an update. However you can use getters without problems. It will just work, as long as everything that you set with objsomething = value
is correctly @tracked
. Also (pure) function calls will just work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With