Any time you have a bunch of nested state like that which needs to be tracked, just tracking the top-level object won't cause updates to the internals of that object to propagate out. You need to track the internal properties, or you need to reset the whole object you're tracking.
You have basically two rough options for dealing with updates to those internal properties:
- If the object has a well-known shape, extract it into a utility class which uses
@tracked
on the fields, and instantiate the utility class when you create the service. Then updates to those fields will update. - If the object is really being used like a hash map, then you have two variant options:
- Use https://github.com/pzuraq/tracked-built-ins, if you don't need IE11 support
- Do a "pure functional update", where you do something like
this.properties = { ...this.properties, foo: newValue };
Of these, (1) is pretty much always going to be the cheapest and have the best performance. Doing (2.1) will be a little more expensive, because it requires the use of a Proxy
, but not enough that you would normally notice. Doing (2.2) will end up triggering a re-render for every property in the properties
used anywhere in the app, even if it didn't change.
In the case you've described, it appears the fields are well known, which means you should reach for that class. The solution might look something like this:
import Service from '@ember/service';import { action } from '@ember/object';import { tracked } from '@glimmer/tracking';class TheProperties { @tracked id; @tracked foo; @tracked bar;}export default class MyService extends Service { properties = new TheProperties(); @action updateProperty(name, value) { this.properties[name] = value; }}
Note that @tracked
installs getters and setters in place of plain class properties, so if you need to use this for a JSON payload somewhere or similar, you'll also want to implement toJSON
on the utility class:
class TheProperties { @tracked id; @tracked foo; @tracked bar; toJSON() { let { id, foo, bar } = this; return { id, foo, bar }; }}