Modeling a dynamic data structure with Ember Data


#1

[Originally a SO question, but now thinking this might be the more appropriate venue]

I am looking for a good way to model a dynamic data structure in Ember Data. I am building something like MailChimp, and the object will hold the content the user enters into various WYSIWYG areas.

The areas will be named, so the resulting object will look like this:

copy = {
  heading: "Buy our new product!",
  body1: "Here are the reasons you should buy..",
  body2: "90 day guarantee"
};

However, the properties of the copy object will change, and aren’t going to be pinned down to anything in particular.

The copy object is part of a LandingPage model:

// models/landing-page.js

export default DS.Model.extend({
  options: DS.attr(),
  copy: DS.attr() // or belongsTo?
});

I’m looking for a strategy to model/persist this in Ember Data.

  1. If the copy property on my model is just a POJO, I need to update the POJO and re-set it on my landingPage model every time a single property changes, to trigger Ember’s watches. This is cumbersome and limiting.
  2. If copy is a separate model, what do I need to do to tell ED that different copy instances will have different properties?
  • Also, copy will probably be persisted as an embedded, id-less object. Does this affect this strategy?

Any other possibilities?


#2

I’ve never attempted a problem quite like what you’re describing (but one I may face in the not-too-distant future), but my first thought is wether the copy object needs to be an POJO. Were it an array, you’ll be able to bind to those changes much more simply.

Perhaps something like:

// models/landing-page.js
export default DS.Model.extend({
  options: DS.attr(),
  copy: DS.hasMany("copy")
});

// models/copy.js
export default DS.Model.extend({
  type: DS.attr(),
  text: DS.attr()
});

That way you can observe copy.@each when a new copy is added or removed; or copy.@each.{text,type} when any of the properties on a copy model is changed.

You did mention that copy would be persisted as an embedded id-less object. Is that mandatory? If it is, then the solution may not be in how you’re building your model, but in your Serializer & Adapter and how you’re persisting the data. There, the format of the payload coming in and going out is less relevant.


#3

Maybe you’re right, and there’s no reason for me not to use separate models here.

I see how I could write custom serializers/adapters to handle the payload, but doesn’t Ember Data expect ids for each model (in the actual Ember application)?


#4

When serializing those related records, you could create a UUID that would only be used for that particular session. It’s a bit of a hack, but as long as that ID doesn’t need to be the same from session to session for the same pieces of data, then I don’t see the harm…


#5

Thanks, this felt dirty but I’ll give it a try.

Seems like there should be some layer to add models that don’t correspond directly to server-side resources. Still feel like I’m missing something here.


#6

I agree that it feels dirty…but, I suppose this type of scenario is exactly what I think was in mind when allowing us to write our own adapters.

That being said, I’ll be curious what your final solution is.


#7

I had to deal with a similar issue

	App.Attachment = DS.Model.extend({
	  data:DS.attr(),
	  card:DS.belongsTo('item',{async:true}),
	})

	App.item = DS.Model.extend({
	  title:DS.attr(),
	  attachments:DS.hasMany('attachment',{async:true}),
              type:DS.attr('string')
	})

for each different type that the item may be, a different pojo will be added to the data attribute. if you change the pojo emberdata sees it as the model has changed so it will render the template normally

I have been using this method for a while with no problems as yet


#8

@samselikoff, I am required to implement this sort of feature now and was wondering if you can share the approach you finally used to implement yours with ember-data.

thanks for sharing.


#9

I ended up making a generic ContentItem model that had name and copy properties, and belonged to a particular template customization. That way, the user creates a new customization for a template, and the template itself knows what ContentItems belong to it. The user can then customize though.

I also made some dynamic components that let me pass in the name and then let the user customize those items.

Does that kind of make sense? Basically each piece of data ended up having an id so it would work nice with MySql/Ember Data.


#10

Yes it does and would be helpful. Thanks.