guides-source
guides-source copied to clipboard
Octane @tracked properties in native classes models do not JSON.stringify
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)
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
@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)
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;
}
}
Just ran into this when creating a changeset to collect form input data, and noticed it wasn't being sent to the server :/