Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't my tracked array update in Ember Octane?

I'm trying out Octane, and for some reason, if I show an array in a template and I add a new object to it, the UI doesn't update. What am I doing wrong?

Here is my template:

<label for="new-field-name">Field Name</label>
<Input id="new-field-name" @value={{this.newFieldName}} type="text" />
<button {{on "click" this.addField}}>Add field</button>

{{#each this.fields as |field|}}
    <p>{{field.name}}</p>
{{/each}}

And the component:

import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

export default class ConfigControlsComponent extends Component {
    @tracked fields = []
    @tracked newFieldName = ''

    @action addField() {
        this.fields.push({
            name: this.newFieldName
        })
        console.log(this.fields)
    }
}

The console.log shows the array with the new object added to it, and the fields array is tracked, but nothing changes when I click the button.

like image 652
handlebears Avatar asked Aug 12 '19 21:08

handlebears


People also ask

What is tracked in Ember JS?

Tracked properties are imported from @glimmer/tracking and used as a decorator to mark the tracked properties. If the property is marked for tracking, the DOM will be re-rendered each time the value of the tracked property changes. Hence, tracked properties are a fundamental change in how Ember handles the state.

What is tracked property?

Tracked properties replace computed properties. Unlike computed properties, which require you to annotate every getter with the values it depends on, tracked properties only require you to annotate the values that are trackable, that is values that: Change over the lifetime of their owner (such as a component) and.

What version is Ember octane?

Which release of Ember is Octane? The Octane Edition was declared for Ember 3.15.


1 Answers

When you use tracked with arrays, you need to "reset" the array so that Ember notices that there has been a change. Try doing this.fields = this.fields after pushing a new object into the array.

Edit: some linters will guard against self-assignment. So, instead, we could pull from immutability patterns, and set using a new array, as shown below.

export default class ConfigControlsComponent extends Component {
  @tracked fields = []
  @tracked newFieldName = ''

  @action addField() { 
    // add this line
    this.fields = [...this.fields, {
      name: this.newFieldName
    }]; 
  }
}

If you are trying to use tracked with an object instead of an array, you have two options:

First, you could create a class where all the properties on the object are tracked:

import { tracked } from '@glimmer/tracking';

class Address {
  @tracked street;
  @tracked city;
}

class Person {
  address = new Address();

  get fullAddress() {
    let { street, city } = this.address;

    return `${street}, ${city}`;
  }
}

Or, second, you could use the same "reset" approach as the array example above.

like image 125
handlebears Avatar answered Nov 15 '22 07:11

handlebears