Tracking Multiple properties in an Object in Ember Octane

Hello,

I need to track more than one property in Object in Glimmer Component, I know we can track them separately like,

@tracked Object.property1;
@tracked Object.property2;

Is there any different approach to track them in a single line similar to computed('Object.{property,property2} in Classic Components?

Hello @Divyaperumal1 I think you’re still sorta thinking in terms of the old reactivity model. I’ll try to clarify what I mean with some examples.

@tracked Object.property1;
@tracked Object.property2;

This isn’t really valid code. I’m not sure if it compiles but it doesn’t have a lot of meaning. Typically what you’d see is more like:

@tracked object = { property1: 231, property2: 456 };

// this getter auto updates anytime "object" is changed
get addPropsOneAndTwo() {
  return this.object.property1 + this.object.property2;
}

@action
updateProperty1(newValue) {
  this.object.property1 = newValue; // this update will not cause a rerender
}

The addPropsOneAndTwo getter will update anytime object is changed, but it won’t auto update if you do something like this.object.property1 = 999. Why? Because autotracking is “shallow” and an object is a complex type. There are basically three ways to make sure “deep tracking” works as expected.

Method 1: set the entire object, not just a sub property

If we rewrite the action to rebuild “object” and set it (replacing the entire object) then the autotracking system will know that object was updated and will recompute the getter

@action
updateProperty1(newValue) {
  this.object = { ...this.object, property1: newValue };
}

Method 2: create your own object which has its own tracked properties:

class MyClass {
  @tracked property1;
  @tracked property2;

  constructor({ property1, property2) {
    this.property1 = property1;
    this.property2 = property2;
  }
}

class MyComponent extends Component {
  @tracked object = new MyClass({ property1: 231, property2: 456 });

  get addPropsOneAndTwo() {
    return this.object.property1 + this.object.property2;
  }

  @action
  updateProperty1(newValue) {
    this.object.property1 = newValue; // this update WILL cause a rerender
  }
}

Now the action will work as expected, because the object is “deep tracked”

Method 3: use tracked built-ins

There’s an addon called tracked-built-ins that provides deep tracked versions of many complex object types.

import { TrackedObject } from 'tracked-built-ins';

class MyComponent extends Component {
  @tracked object = new TrackedObject({ property1: 231, property2: 456 });

  get addPropsOneAndTwo() {
    return this.object.property1 + this.object.property2;
  }

  @action
  updateProperty1(newValue) {
    this.object.property1 = newValue; // this update WILL cause a rerender
  }
}

Conclusion

Any of these three methods should help you “deep track” an object or array or whatever. The right one depends on your needs and use case. Autotracking frees us from the need to observe specific properties, it just requires that we be conscious of what data is tracked and how that data is updated (for complex types).

3 Likes

Thank you @dknutsen , Will try these methods.