I am trying to figure out what the correct Ember.js way to model this project would be, eg. what models, routes and controllers would be needed. I have started a jsBin to work from.
My requirements can be safely reduced down to:
Items & their Options
Dashboard
Navigation
Data
So how would this be structured in Ember?
I've tried to do this once on my own, but it was my first try and I ended up with a pretty ugly setup. I would like to see how someone with Ember experience would approach this:
jsBin Mockup (link)
I've created a series of handlebar templates, but have not taken a stab at what models should exist and what controllers are needed..
Json
{
"Items" : [
{
"Item" : {
"nid" : "3",
"title" : "Hydro",
"image" : "http://bpf.vm/sites/default/files/bpf_things/hydro.jpg",
"properties" : "Baseload, Intermittent",
"values" : {
"Cost" : {
"price" : "6",
"quantity" : null
},
"Percent of Portfolio" : {
"price" : null,
"quantity" : "56"
}
},
"options" : {
"1" : {
"price" : "1512",
"quantity" : "10000"
},
"12" : {
"price" : "825",
"quantity" : "20000"
},
"11" : {
"price" : "550",
"quantity" : "50000"
}
}
}
},
{
"Item" : {
"nid" : "4",
"title" : "Nuclear",
"image" : "http://bpf.vm/sites/default/files/bpf_things/nuclear.jpg",
"id" : "",
"properties" : "Baseload, Predictable",
"values" : {
"Cost" : {
"price" : "8",
"quantity" : null
},
"Percent of Portfolio" : {
"price" : null,
"quantity" : "21"
}
},
"options" : {
"4" : {
"price" : "825",
"quantity" : "10000"
},
"13" : {
"price" : "411",
"quantity" : "15000"
}
}
}
},
{
"Item" : {
"nid" : "5",
"title" : "Natural Gas",
"image" : "http://bpf.vm/sites/default/files/bpf_things/gas.jpg",
"id" : "9",
"properties" : "Baseload, Predictable",
"values" : {
"Cost" : {
"price" : "5",
"quantity" : null
},
"Percent of Portfolio" : {
"price" : null,
"quantity" : "24"
}
},
"options" : {
"7" : {
"price" : "400",
"quantity" : "50000"
},
"10" : {
"price" : "600",
"quantity" : "100000"
}
}
}
}
]
}
In Ember Data, models are objects that represent the underlying data that your application presents to the user. Note that Ember Data models are a different concept than the model method on Routes, although they share the same name.
If your app needs a team of experienced developers for best practices in development- choose Ember. If your app-development process requires sophisticated coding practices, convention over configuration– choose Ember.
I put up a small JSBin http://jsbin.com/IdAXuMar/5/edit
Okay, so after having a chat and a bit of a longer look at it, here are my thoughts on how to simplify this:
You only have one URL, therefore i would go with only one Route and one Controller for now.
The datamodel is quite simple because it is completely hierarchical:
a Display has many Items, an Item has many Options
And because you only ever look at one Display at a time, you do not need the Display as a model at all. If your application evolves and you have multiple Displays at once, it makes sense to implement a Display model, though, and do all JSON requests through that model.
I would implement a single Route and Controller:
App.Router.map(function() {
this.resource('display', path: { 'display/:id' });
});
App.DisplayRoute = Ember.Route.extend({
model: function(params) {
return App.Item.find(params._id);
}
});
the DisplayController has full access on all it's items, as they are set as it's model.
I think You only need one template for now, you can split these into multiple partials later if it's growing out of control.
<script type="text/x-handlebars" data-template-name="display">
{{#each model}}
<!-- access on every item here -->
{{#each option}}
{{#if isSelected}}
this option is selected
{{/if}}
<!-- access on every option here -->
<a {{action selectOption this}} href=''> Select this option</a>
{{/each}}
{{/each}}
</script>
Note the selectOption action: when calling this and passing the option, you can then set the selected state directly on the option itself, which will immediately reflect in the view.
App.DisplayController = Ember.ArrayController.extend({
// add computed properties here..
actions: {
selectOption: function(option) {
option.set('isSelected', true);
}
}
});
To get the items from the server, you could call App.Item.find() and then pass the display's id. That is not a 100% conventional, as you would be expected to pass the Item's id here, but i think for this purpose it's okay. so this method would look something like
App.Item = Ember.Option.extend({
selected: false
// add computed properties here
});
App.Item.reopenClass({
// retrieves the items from the server
find: function(displayId) {
var url = "/game/json" + displayId;
var items = new Ember.A();
Ember.$.getJSON().success(function(data) {
data.items.forEach(function(jsonItem) {
var item = Ember.Item.create({
nid: jsonItem.nid,
title: jsonItem.title,
image: jsonItem.image
});
item.set('options', new Ember.A());
jsonItem.options.forEach(function(option) {
var option = Ember.Option.create({
// set option properties
});
emberItem.get('options').pushObject(option);
})
})
});
return items;
}
});
I hope that helps you get started and perhaps makes it a little easier to transfer your concept to Ember. If you have questions regarding for example how to save everything back to the server, shoot :)
Here's the beginnings of an answer:
Models
I think I only need three models here. The dashboard is a major player in this app, but it does not have any data of it's own.
Controllers
Earlier I was totally missing the concept of ArrayControllers. Generally, anything that is a collection will need an ArrayController to represent it, rather than a plain ember ObjectController. My 'Items' will need one, but I don't think 'Options' will because Options are children of Item, and can use Item/Items as a proxy.
Templates
The indentation here represents templates that render other templates. For instance my Display template contains {{render dashboard}}
and {{render items}}
.
Routes
This is still very hazy. Routes seem to play many roles (mapping urls to models, setting models for controllers, maybe other stuff??). At the moment the only url I can think of needing is:
Other routes:
setupController
: sets the controller to a blank/saved displayredirect
: just redirects to the display route (essentially the root of the app)model
: sets a given display as the modelafterModel
: load up the items specified by the displayI think that's all. This is a simple app and once I have the Items loaded for a Display then the app just changes the display for the screen. There are user selections, but they are boolean flags (eg setting isSelected on an Item should alter the data shown by the dashboard) - these selections don't require any navigation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With