How to represent arrays within ember-data models?
Solution 1
Well... It was a little bit difficult but mixing all answers in this post I made it work.
Firstly, you should create a transform for the new type "array":
DS.ArrayTransform = DS.Transform.extend({
deserialize: function(serialized) {
return (Ember.typeOf(serialized) == "array")
? serialized
: [];
},
serialize: function(deserialized) {
var type = Ember.typeOf(deserialized);
if (type == 'array') {
return deserialized
} else if (type == 'string') {
return deserialized.split(',').map(function(item) {
return jQuery.trim(item);
});
} else {
return [];
}
}
});
App.register("transform:array", DS.ArrayTransform);
Now, in your model, just use it as another attr:
App.myModel = Ember.Model.extend({
name : DS.attr('string'),
cont : DS.attr('array')
}
And we are done. Remember, when adding elements to the array, to use pushObject.
In a controller:
this.get('model.cont').pushObject('new Item');
I hope this helps someone.
Solution 2
I use a raw
transform, which looks like this in ember-data revision 11:
DS.RESTAdapter.registerTransform('raw', {
deserialize: function(serialized) {
return serialized;
},
serialize: function(deserialized) {
return deserialized;
}
});
Then, within a model, I do this:
App.MyModel = Ember.Model.extend({
anArray: DS.attr('raw')
});
and can use anArray
like a regular array anywhere.
Solution 3
Here is an example of creating a custom array type in Ember-Data (version 10):
DS.JSONTransforms.array =
# If the outgoing json is already a valid javascript array
# then pass it through untouched. In all other cases, replace it
# with an empty array. This means null or undefined values
# automatically become empty arrays when serializing this type.
serialize: (jsonData)->
if Em.typeOf(jsonData) is 'array' then jsonData else []
# If the incoming data is a javascript array, pass it through.
# If it is a string, then coerce it into an array by splitting
# it on commas and trimming whitespace on each element.
# Otherwise pass back an empty array. This has the effect of
# turning all other data types (including nulls and undefined
# values) into empty arrays.
deserialize: (externalData)->
switch Em.typeOf(externalData)
when 'array' then return externalData
when 'string' then return externalData.split(',').map((item)-> jQuery.trim(item))
else return []
Now you can use the custom type in a model attribute:
App.CalenderWeek = DS.Model.extend
selected_days = DS.attr('array')
And now when you fetch a record with:
App.CalendarWeek.find(1)
both of these incoming json records will deserialize correctly into an Array:
{ selected_days: ['Monday', 'Tuesday', 'Saturday'] }
or
{ selected_days: 'Monday, Tuesday, Saturday' }
Solution 4
In Ember Data 1.0.0 Beta, one has been given the ability to "register" his or her custom transform "subclass". I'd prefer to refer to it as an extended DS.Transform
object.
DS.ArrayTransform = DS.Transform.extend({
deserialize: function(deserialized) {
// ...
return deserialized;
},
serialize: function(serialized) {
// ...
return serialized;
}
});
App.register('transform:array', DS.ArrayTransform);
Solution 5
If you absolutely need a custom data structure to be exchanged with your server, you can enrich DS.attr.transforms
and declare a new array
codec, for example.
See source code for existing attribute codecs implementation. It is a good place to start adding your own.
dechov
Updated on September 12, 2020Comments
-
dechov over 3 years
Is it necessary to use
DS.hasMany
pointing to aDS.Model
when a model contains an array? Even if the array elements are not really models (no IDs or endpoints of their own)? Is there a better way?I am using
DS.hasMany
, but my extendedDS.RESTAdapter
is throwing me a 404 trying to access the model, even though I'm never callingfind
on it, andhasMany
is called with{ embedded: true }
. I am seeing this error for the first time (apparently in connection with this model, since it goes away without it):Uncaught Error: assertion failed: Emptying a view in the inBuffer state is not allowed and should not happen under normal circumstances. Most likely there is a bug in your application. This may be due to excessive property change notifications. ember-latest.js:43
What does this mean and what might be causing it?
Here's the stack trace:
Ember.assert ember-latest.js:43 Ember.View.states.inBuffer.empty ember-latest.js:13644 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12257 Ember.CollectionView.Ember.ContainerView.extend.arrayWillChange ember-latest.js:14477 invokeAction ember-latest.js:3193 iterateSet ember-latest.js:3175 sendEvent ember-latest.js:3323 Ember.Array.Ember.Mixin.create.arrayContentWillChange ember-latest.js:6963 Ember.ArrayProxy.Ember.Object.extend.arrangedContentArrayWillChange ember-latest.js:9281 Ember.ArrayProxy.Ember.Object.extend._arrangedContentWillChange ember-latest.js:9235 invokeAction ember-latest.js:3193 iterateSet ember-latest.js:3175 sendEvent ember-latest.js:3323 notifyObservers ember-latest.js:1872 Ember.notifyBeforeObservers ember-latest.js:2016 propertyWillChange ember-latest.js:2594 iterDeps ember-latest.js:2077 dependentKeysWillChange ember-latest.js:2092 propertyWillChange ember-latest.js:2592 set ember-latest.js:1416 DS.Model.Ember.Object.extend.dataDidChange ember-data-latest.js:3145 Map.forEach ember-latest.js:1273 OrderedSet.forEach ember-latest.js:1145 Map.forEach ember-latest.js:1271 DS.Model.Ember.Object.extend.dataDidChange ember-data-latest.js:3128 invokeAction ember-latest.js:3193 iterateSet ember-latest.js:3175 sendEvent ember-latest.js:3323 notifyObservers ember-latest.js:1872 Ember.notifyObservers ember-latest.js:1999 propertyDidChange ember-latest.js:2632 Ember.Observable.Ember.Mixin.create.propertyDidChange ember-latest.js:7917 Ember.Observable.Ember.Mixin.create.notifyPropertyChange ember-latest.js:7930 didChangeData ember-data-latest.js:2053 Ember.StateManager.Ember.State.extend.sendRecursively ember-latest.js:15446 Ember.StateManager.Ember.State.extend.send ember-latest.js:15431 DS.Model.Ember.Object.extend.send ember-data-latest.js:3058 DS.Store.Ember.Object.extend.load ember-data-latest.js:1737 DS.Store.Ember.Object.extend.loadMany ember-data-latest.js:1763 embeddedFindRecord ember-data-latest.js:3434 hasAssociation ember-data-latest.js:3459 ComputedPropertyPrototype.get ember-latest.js:2968 get ember-latest.js:1362 getPath ember-latest.js:1484 get ember-latest.js:1355 getWithGlobals ember-latest.js:4041 Binding.connect ember-latest.js:4140 connectBindings ember-latest.js:4600 finishPartial ember-latest.js:4610 Class ember-latest.js:8315 Ember.Mixin.create.create ember-latest.js:8457 Ember.View.Ember.Object.extend.createChildView ember-latest.js:13179 Ember.View.states.inBuffer.appendChild ember-latest.js:13622 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12239 Ember.View.Ember.Object.extend.appendChild ember-latest.js:13058 EmberHandlebars.ViewHelper.Ember.Object.create.helper ember-latest.js:18687 (anonymous function) ember-latest.js:18844 (anonymous function) ember-latest.js:19043 (anonymous function) ember-latest.js:19208 (anonymous function) (anonymous function) handlebars-1.0.0.beta.6.js:1512 Ember.View.Ember.Object.extend.render ember-latest.js:12223 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.View.states.inBuffer.appendChild ember-latest.js:13625 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12239 Ember.View.Ember.Object.extend.appendChild ember-latest.js:13058 EmberHandlebars.ViewHelper.Ember.Object.create.helper ember-latest.js:18687 (anonymous function) ember-latest.js:18844 program2 (anonymous function) handlebars-1.0.0.beta.6.js:1529 Ember.View.Ember.Object.extend.render ember-latest.js:12223 Ember._HandlebarsBoundView.Ember._MetamorphView.extend.render ember-latest.js:18075 Ember.wrap.newFunc ember-latest.js:949 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.View.states.inBuffer.appendChild ember-latest.js:13625 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12239 Ember.View.Ember.Object.extend.appendChild ember-latest.js:13058 bind ember-latest.js:18129 (anonymous function) ember-latest.js:18199 (anonymous function) ember-latest.js:18271 program1 (anonymous function) handlebars-1.0.0.beta.6.js:1529 Ember.View.Ember.Object.extend.render ember-latest.js:12223 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.ContainerView.Ember.View.extend.render ember-latest.js:14078 Ember.View.Ember.Object.extend.forEachChildView ember-latest.js:12486 Ember.ContainerView.Ember.View.extend.render ember-latest.js:14077 Ember.wrap.newFunc ember-latest.js:949 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.View.states.inBuffer.appendChild ember-latest.js:13625 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12239 Ember.View.Ember.Object.extend.appendChild ember-latest.js:13058 EmberHandlebars.ViewHelper.Ember.Object.create.helper ember-latest.js:18687 (anonymous function) ember-latest.js:18844 (anonymous function) ember-latest.js:19043 (anonymous function) ember-latest.js:19208 (anonymous function) (anonymous function) handlebars-1.0.0.beta.6.js:1512 Ember.View.Ember.Object.extend.render ember-latest.js:12223 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.ContainerView.Ember.View.extend.render ember-latest.js:14078 Ember.View.Ember.Object.extend.forEachChildView ember-latest.js:12486 Ember.ContainerView.Ember.View.extend.render ember-latest.js:14077 Ember.wrap.newFunc ember-latest.js:949 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.View.states.inBuffer.appendChild ember-latest.js:13625 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12257 Ember.View.Ember.Object.extend.appendChild ember-latest.js:13058 EmberHandlebars.ViewHelper.Ember.Object.create.helper ember-latest.js:18687 (anonymous function) ember-latest.js:18844 (anonymous function) ember-latest.js:19624 (anonymous function) ember-latest.js:18167 (anonymous function) (anonymous function) handlebars-1.0.0.beta.6.js:1512 Ember.View.Ember.Object.extend.render ember-latest.js:12223 Ember.View.Ember.Object.extend.renderToBuffer ember-latest.js:12872 Ember.View.Ember.Object.extend.createElement ember-latest.js:12669 Ember.View.states.preRender.insertElement ember-latest.js:13558 Ember.View.Ember.Object.extend.invokeForState ember-latest.js:12257 invoke ember-latest.js:3428 iter ember-latest.js:3475 RunLoop.flush ember-latest.js:3531 RunLoop.end ember-latest.js:3447 Ember.run.end ember-latest.js:3639 autorun ember-latest.js:3705
Thanks for any help.
Update: This fiddle works (with example from docs), but how could those objects be represented if the tags aren't real models (i.e. don't have IDs)?
-
Braedon Wooding about 11 yearsThis doesn't seem to work with EM 11. Shreyans submission does though.
-
Mike Aski about 11 yearsIndeed a good implementation. I've got the same in my apps... :-)
-
pooja upadhyay about 11 yearsIf using this solution to render your data in a partial - look at the workaround here -> github.com/emberjs/ember.js/issues/1990#issuecomment-13855767
-
Pascal Zajac over 10 yearsThis worked perfectly, thanks for the example and explanation.
-
Damon Bauer over 10 yearsThis worked perfect for my needs (a simple array in a FIXTURE), with an {{#each}} to display the array values. Thanks!
-
J. Mitchell over 10 yearsThis doesn't set the isDirty flag on the model when I change selected_days. Is this a known issue?
-
Patrick Fisher about 10 yearsThis is the method shown in the documentation, so I'd call it the "Ember way": emberjs.com/api/data/classes/DS.Transform.html
-
aceofspades about 10 yearsThis syntax appears to be deprecated, see @PatrickFisher's link
-
BJ McDuck almost 10 yearsWhy not set this as the answer?
-
nruth almost 9 yearsAn advantage is this lets you set a DS.attr defaultValue, where as DS.attr(null, defalutValue: []) doesn't work. I don't see a deprecation notice? Which version / where on the page?
-
Gustavo Alexandre over 8 yearsCould you pl. let us know in which file this code needs to be added.
-
rxgx over 8 years@RajaNagendraKumar Add it to the file where you have access to
DS
variable. Do you have that as an import or global variable? -
iOS dev about 7 years@J.Mitchell were you able to fix the isDirty issue. Even, I cannot see the model getting updated with the values changed in the handlebars
-
iOS dev about 7 yearshey @BrandonJMcKay, how to edit the array and save it back to the payload. I dont see any bindings when editing the existing array.
-
BJ McDuck about 7 years@iOSdev, umm... why not ask @Bommox? I didn't provide any information here, but I think you might be looking for a serializer, or an adapter. A transform modifies the data incoming/outgoing, but it's meant for specific data types. Nothing more. If you're using the word payload, I'm thinking you want a serializer, or an adapter.