ember-learn / guides-source

This repository contains the Ember.js Guides
https://guides.emberjs.com/
MIT License
158 stars 497 forks source link

Octane @tracked properties in native classes models do not JSON.stringify #1138

Open void-mAlex opened 5 years ago

void-mAlex commented 5 years ago

declaring models as util classes and using @tracked property (as described here https://octane-guides-preview.emberjs.com/release/state-management/tracked-properties/#toc_tracked-properties-in-custom-classes) causes any such model passed to a JSON.stringify call to omit any tracked properties from the json output. in short doing this

class Person {
  @tracked firstName;
  @tracked lastName;

  constructor(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}
JSON.stringify(new Person('Tobias', 'Bieniek')); // --> "{}"

solution would be implementing toJSON method in the class

the guides should be updated to reflect that as it's very likely someone would want to pass those models to a persistence layer of any sort (this would be a problem even with localStorage)

rwjblue commented 5 years ago

Indeed this is a problem largely due to the way that @tracked itself is currently implemented. @tracked set's up getters and setters on the prototype, and JSON.stringify won't include them since they are not instance properties.

More information over here https://github.com/emberjs/ember.js/issues/18220

void-mAlex commented 5 years ago

@rwjblue do you know how ember data works around this problem as I would expect that @attr in models will have the same issue and reading the link you posted that would have a performance impact with using the data models (please correct me if I'm missing something)

Kilowhisky commented 4 years ago

I just ran into this during my conversion to Octane and found this (hackey) solution.

https://stackoverflow.com/a/50785428/1148118

I just created a base class and used it to implement the override replacement.

export class BaseClass {
   toJSON() {
        // fields that are @tracked don't work with JSON, fix that. https://github.com/ember-learn/guides-source/issues/1138
        // Implemented based off of this https://stackoverflow.com/a/50785428/1148118
        const jsonObj = Object.assign({}, this);
        const proto = Object.getPrototypeOf(this);
        for (const key of Object.getOwnPropertyNames(proto)) {
            const desc = Object.getOwnPropertyDescriptor(proto, key);
            const hasGetter = desc && typeof desc.get === 'function';
            if (hasGetter) {
                jsonObj[key] = this[key];
            }
        }
        return jsonObj;
    }
}
amk221 commented 4 years ago

Just ran into this when creating a changeset to collect form input data, and noticed it wasn't being sent to the server :/