ember-changeset: 'getting' a Moment instance on a changeset returns a relay instead of that instance

When having a Moment instance on a changeset, eg.: set(changeset, 'startDate', moment()), and if you then later do get(changeset, 'startDate') it will - instead of returning the Moment instance on the changeset - return a relay with ‘startDate’ as key.

I’m unsure if this is a 100% a bug, as the Moment instance is an object so ember-changeset thinks it has to create a relay, but it would be nice if there were a way to deal with this (eg. defining keys for which no relay should be created, as I’m not going to directly get or modify the internals of the Moment instance).

@nucleartide

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 35 (9 by maintainers)

Most upvoted comments

Just to notify everyone, 2.0.0-beta.0 has been published for ember-changeset and ember-changeset-validations. Give it a shot! @sevab i think it might fix your issue but don’t quote me on it 😃

Got a similar problem, setting a moment() date on a changeset and then getting it back does not return the Moment object. setup:

  • ember-changeset 3.3.1
  • ember-source 3.18.0
  • ember-cli-moment-shim

After tracking all the callbacks the pivot point I found was in ember-changeset/addon/index.js in the get method (line 150).

My temporary hack to make it work is to trick the get method into thinking that a Moment object is a belongsTo relationship (better to have a specific or generalized implementation for this):

now = moment()
now.constructor.prototype.isLoading = true
now.constructor.prototype.isLoaded = true
now.constructor.prototype.isNew = true
now.constructor.prototype.hasDirtyAttributes = true

hopefully this saves somebody the time!

Just ran across this issue, identical problem to what was described by most (changeset + moment + ember-power-calendar) Version 2.0.0 everything works. Thanks @snewcomer! You rawk.

@snewcomer all seems to works with 2.0, thanks!

Though In handlebars had to switch selected=(hash start=changeset.startDate.content end=changeset.endDate.content) to selected=(hash start=changeset.startDate end=changeset.endDate).

Which is a changed behaviour, but more convenient.

I’m still having this issue (or possibly a similar-and-related issue, since mine is happening in the JS for a component and not in a template).

I put together a new app with enough code to reproduce the problem: https://github.com/pgengler/ember-changeset-issue/tree/problems-with-moment

To reproduce

  • check out the problems-with-moment branch of that repo
  • yarn install
  • ember s
  • Visit http://localhost:4200/recipes/1
  • Note the failing assertion in the JS console

Going to close for now! Lmk if anybody has any questions!

So my only question is what if val is new Dog() or something like that?

It depends:

  • class Dog extends EmberObject{}: Will return a relay cause Dog extends EmberObject and therefore typeof(new Dog()) === 'instance' is true.
  • function Dog() {}: Will return instance of Dog cause Object.getPrototypeOf(val) === Object.prototype is false (and it’s not an instance of EmberObject).
  • function Dog() {}; Dog.prototype = Object.prototype: Will return a relay cause Object.getPrototypeOf(val) === Object.prototypeistrue` (but I hope nobody is doing something like that).

Also, typeOf returns the correct types if I’m not mistaken. e.g. Ember.typeOf([]) === “array”

It depends what you consider “the correct type”. I’m arguing that type "object" of ember’s typeOf function is to broad for our use case:

Ember.typeOf({}) === 'object';
Ember.typeOf(moment()) === 'object';
Ember.typeOf(new Dog()) === 'object';

@snewcomer Your test is fine. While trying to debug I noticed that the bug only occurs if changeset template helper is used. Here is another ember-twiddle demonstrating that it’s working fine if changeset is constructed in code: https://ember-twiddle.com/eeb4e12e66b114c12e7204b218d359a2?openFiles=templates.application.hbs%2C

This is the ember twiddle showing that it’s not working if template helper is used: https://ember-twiddle.com/f38bf913c6c44079ba0c84c148cc9f05?openFiles=templates.application.hbs%2C


Debugged further and noticed that the bug is only occuring if ember getter is used and the value is proxied to content:

class Moment {}

let c = new Changeset({
  foo: new Moment()
});
c.set('bar', new Moment());
    
console.log(c.get('foo') instanceof Moment); // true
console.log(get(c, 'foo') instanceof Moment); // false
console.log(c.get('bar') instanceof Moment); // true
console.log(get(c, 'bar') instanceof Moment); // true

Here is an ember-twiddle: https://ember-twiddle.com/a5ea906707f67f978454d0164b1da8ed?openFiles=controllers.application.js%2C

This is not covered by your test since you are only testing getter after setting the value.

Agreed. I’ll find time this week to put up a fix if possible. After that is fixed, let’s release 1.5 proper!

I don’t think this is fixed. Here is a reproduction for v1.5.0-beta.0: https://ember-twiddle.com/f38bf913c6c44079ba0c84c148cc9f05?openFiles=templates.application.hbs%2C It’s the same if you downgrade ember-changeset to 1.4.2-beta.0.

If accessing the moment object throw changeset (e.g. using moment-format helper as in twiddle) this is blowing up due to .get() assertion:

Assertion Failed: You attempted to access the `_isAMomentObject` property (of <(unknown):ember216>).
Since Ember 3.1, this is usually fine as you no longer need to use `.get()`
to access computed properties. However, in this case, the object in question
is a special kind of Ember object (a proxy). Therefore, it is still necessary
to use `.get('_isAMomentObject')` in this case.

Please note that this assertion is triggered by moment.js code.

The regression has been added in 1.4.0. It’s working fine for 1.3.0.