# Another way to track nested data structures

**URL:** https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978
**Category:** Development
**Tags:** plugin-api, rest-api
**Created:** [March 19, 2025, 3:24pm UTC](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978 "2025-03-19T15:24:00Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![bitmage](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/bitmage/32/389881_2.png) [@bitmage](https://meta.discourse.org/u/bitmage)
#### Post date: [March 19, 2025, 3:24pm UTC](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978/1 "2025-03-19T15:24:00Z")

</div>

`@tracked` state of an array or object within a glimmer component does not trigger updates when you change a member of the array/object.

[This topic talks about some options](https://meta.discourse.org/t/problem-tracking-nested-structure/320886) to get your view to properly update. I wanted to add another way, as the options talked about there did not work for me.

How I solved this is: Rather than assign one element at a time, assign the whole array at once. This same strategy would work with an object or any other data structure.

In a glimmer component:

```javascript
@tracked categories = [];

constructor() {
  super(...arguments);
  this.loadAllData();
}

async loadAllData() {
  const categories = []
  const waiting = this.siteSettings.county_fence_print_categories.split('|').map(async (cid, index) => {
    const data = await this.loadData(`/c/${cid}/l/latest.json?period=monthly`)
    return data.topic_list.topics
  })

  // THIS IS THE LINE TO NOTICE
  // Because we use = directly on the array, it will trigger an update.
  // Whereas pushing to the array or setting elements by index would not trigger an update.
  this.categories = await Promise.all(waiting)
}

async loadData(url) {
  try {
    const data = await ajax(url);
    //console.log(`Got data for ${url}:`, data)
    return data
  } catch (error) {
    console.error(`Failed to get data for ${url}:`, error);
  }
}

```

You could do this with a partial update as well. The important thing is for Javascript to detect that a _different value_ is being assigned. So while `.concat` will work, because it’s generating a new array distinct from the old one:

```javascript
this.categories = this.categories.concat(newValue)

```

Using `.push` will probably _not_ work, because the resulting array is the same object ID as the original, thus Javascript thinks that nothing has changed.

```javascript
this.categories.push(newValue)
this.categories = this.categories

```

If you are working with an object, an easy way to generate a new one is with `Object.assign()` - which creates a new, extended data structure, like `.concat` above.

This has long been the case for other frameworks such as Vue.js as well - you can find topics about this going back for 10 years. It has to do with the way it’s being implemented in Javascript, probably either getters/setters on the parent object or the `observe` API. But if it’s implemented with the observe API then there’s a little bit less of an excuse for this behavior, since it would be [easy to toggle the subtree flag](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver/observe#subtree)… Maybe they choose not to do this for performance concerns when watching a deeply nested structure? But I digress, these are implementation details of the underlying libraries. The workaround above should help you navigate this.

---

<div class="post-metadata">

### Author: ![Arkshine](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/arkshine/32/298682_2.png) [@Arkshine](https://meta.discourse.org/u/Arkshine)
#### Post date: [March 19, 2025, 3:32pm UTC](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978/2 "2025-03-19T15:32:13Z")

</div>

> [@bitmage](#):
>
> `@tracked` state of an array or object within a glimmer component does not trigger updates when you change a member of the array/object.

I wonder if `TrackedArray` would help here?  
I did not dive more than that. I just remembered that Discourse code uses this here and there.

`import { TrackedArray, TrackedObject } from "@ember-compat/tracked-built-ins";`

---

<div class="post-metadata">

### Author: ![bitmage](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/bitmage/32/389881_2.png) [@bitmage](https://meta.discourse.org/u/bitmage)
#### Post date: [March 19, 2025, 3:33pm UTC](https://meta.discourse.org/t/another-way-to-track-nested-data-structures/357978/3 "2025-03-19T15:33:42Z")

</div>

Imagine if this were documented. 😆

But yes, that seems designed precisely for this scenario.
