template syntax for related data - ember.js

This seems like it should be simple. Suppose I have the following model:
App.Folder = DS.Model.extend({
folder_id: DS.attr('number'),
folder_name: DS.attr('string'),
items: DS.hasMany('App.Item')
});
App.Item = DS.Model.extend({
item_id: DS.attr('number'),
folder_id: DS.attr('number'),
item_name: DS.attr('string'),
folder: DS.belongsTo('App.Folder')
});
...and the following data:
App.Folder.FIXTURES = [
{
id: 1,
folder_name: 'My First Folder',
items: [100]
},
{
id: 2,
folder_name: 'Another Folder',
items: [101]
},
{
id: 3,
folder_name: 'Folder 3',
items: [102]
}
];
App.Item.FIXTURES = [
{
id: 100,
folder_id: 1,
item_name: 'This is an item'
},
{
id: 101,
folder_id: 2,
item_name: 'A cleverly named item'
},
{
id: 102,
folder_id: 3,
item_name: 'This one is also an item in a folder'
}
];
Now, in my "item" template, shouldn't I be able to do something like this to show the folder related to an item:
<script type="text/x-handlebars" data-template-name="snapshot">
<div class="row-fluid property-row-alt">
<div class="span4 property-label">item name:</div>
<div class="span8">{{ item_name }}</div>
</div>
<div class="row-fluid property-row">
<div class="span4 property-label">folder:</div>
<div class="span8">{{ folder.folder_name }}</div>
</div>
</script>
"folder.folder_name" is the key syntax I'm trying to nail down here. Maybe this isn't possible, but I'm hoping to get the related folder and drill down into it's folder_name inside my item template. Can I do this in Ember? Using the latest versions.

Related

Get data from ember data bind it to a widget in view

I have a router that returns data from the data model.
I want to use this data to bind it to a widget in a view.
Model:
myApp.Unit = DS.Model.extend({
active: DS.attr('boolean'),
allowdecimals: DS.attr('boolean'),
name: DS.attr('string'),
count: DS.attr('number'),
});
Router:
myApp.EunitsRoute = Ember.Route.extend({
model: function() {
return this.store.find('unit');
},
setupController: function(controller, model) {
this._super(controller, model);
controller.set('units', model);
},
actions: { ...
In the view I expect an object formated as follows:
[ {"id": 1,"active": true,"allowdecimals": true,"name": "Pint","count": 8},
{"id": 2,"active": true,"allowdecimals": true,"name": "Each","count": 8},
...]
What I am getting now in the view is an object:<DS.RecordArray:ember400>
View:
var source10 = {
datatype: "array",
datafields: [
{ name: 'id' },
{ name: 'name' },
{ name: 'allowdecimals' },
{ name: 'active' },
{ name: 'count' }
],
localdata: controller.get('units')
};
var dataAdapter10 = new $.jqx.dataAdapter(source10);
$("#eunits_grid").jqxGrid({
pageable: true,
theme: 'energyblue',
autorowheight : true,
rowsheight : 50,
pagesize: 10,
source: dataAdapter10,
....
Template:
<script type="text/x-handlebars" data-template-name="eunits">
<div class="col-md-12">
<h3 class="page-header">Edit Units</h3>
{{#if adding}}
{{view AddnewunitView}}
{{/if}}
{{view UnitsView id='eunits_grid'}}
</div>
</script>

Loading state for ApplicationRoute

Using: ember 1.7.0
I have some server-side data that I want to load up in my ember app before any routes are transitioned to. Multiple (but not all) of my other routes / controllers need this data. I was thinking that I could just load up this data in the ApplicationRoute model method. It works fine, but does not display a loading state.
Is it possible to have the ApplicationRoute display a loading state until it's model promise gets resolved.
Here's a jsbin illustrating the problem: http://jsbin.com/soqivo/1/
Thanks for the help!
Update:
As of 1.11.0 release, it should be possible to define a loading substate for the application route.
TL;DR;
I think this is by design, but not a design flaw. This particular issue is happening because that long model request is taking place in ApplicationRoute#model when it should be in IndexRoute#model. Move that promise/request into the index route and it should be fine. If you must add stuff to the application controller, consider this, combined with something that says "loading" in your index.html file while the app is waiting.
Why
Ember.Route has a number of hooks that we often override so it does what we want instead of a default implementation. The most obvious hook being model and setupController. But sometimes we simply don't write the setuptController method because it does what we want it to do already (given one just wants to set the model into the controller). But regardless of these methods being overridden, they will run as part of an internal workflow anyway. This workflow has a number of steps that are not often discussed because they already do what we want and we tend to forget about them and their importance, and, as for this particular issue, the order in which these methods get called in the route life cycle.
App = Ember.Application.create();
App.logs = Ember.ArrayProxy.create({
content: []
});
App.Router.map(function() {
this.resource('posts', function() {});
});
function loggingAlias(property) {
return function() {
App.logs.pushObject(this._debugContainerKey + ' ' + property);
return this._super.apply(this, arguments);
};
}
App.LoggingRoute = Ember.Route.extend({
enter: loggingAlias('enter (private)'),
exit: loggingAlias('exit (private)'),
activate: loggingAlias('activate'),
deactivate: loggingAlias('deactivate'),
serialize: loggingAlias('serialize'),
deserialize: loggingAlias('deserialize (private)'),
model: loggingAlias('model'),
setupController: loggingAlias('setupController'),
afterModel: loggingAlias('afterModel'),
beforeModel: loggingAlias('beforeModel'),
renderTemplate: loggingAlias('renderTemplate'),
redirect: loggingAlias('redirect')
});
App.LogsController = Ember.ArrayController.extend({
content: App.logs,
actions: {
clearLogs: function() {
App.logs.clear();
}
}
});
App.ApplicationRoute = App.LoggingRoute.extend();
App.PostsRoute = App.LoggingRoute.extend();
App.PostsIndexRoute = App.LoggingRoute.extend();
/* Put your CSS here */
html,
body {
margin: 20px;
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Ember Route Hook Order" />
<meta charset="utf-8">
<title>Ember Route Hook Order</title>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/normalize/2.1.0/normalize.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.2.1.js"></script>
<script src="http://builds.emberjs.com/beta/ember.js"></script>
</head>
<body>
<script type="text/x-handlebars">
<strong>Note:</strong> <em>
MilkyWayJoe says: I didn't write this. I have found in jsbin at: http://jsbin.com/rolo/2/edit?output
<br />
Added here in case the link goes kaput just to point out the order of Ember.Route internal workflow steps
</em>
<br />
<br />{{link-to 'Index' 'index'}} {{link-to 'Posts' 'posts'}} {{outlet}} {{render 'logs'}}
</script>
<script type="text/x-handlebars" id='logs'>
<h3>Logged Method Calls</h3>
<a href="#" {{action 'clearLogs'}}>Clear Logs</a>
<ul>
{{#each}}
<li>{{this}}</li>
{{/each}}
</ul>
</script>
</body>
</html>
Since renderTemplate is the last to get called so it only makes sense that it doesn't render anything until the promise(s) within a given route get resolved.
For child routes, that's totally fine because their loading substate will have some type of canvas to draw onto, since a parent-already-loaded-living-and-breathing-route has been loaded prior this route even being instantiated. But that's not true for the ApplicationRoute since it has no parent route or template to rely upon, thus rendering a blank page until all promises get resolved.
Working snippet
The next best thing is moving any long running requests to a child route. As the proposed solution, I've moved your 3 sec promise to IndexRoute#model since this route will run anyway and is the direct child of ApplicationRoute by default. I would say reserve the application route or controller for handling error events instead.
App = Em.Application.create({
displayName: 'Test.App'
});
App.Router.map(function() {
this.resource('files', function() {
this.route('index', {path: '/'});
this.resource('file', { path: ':file_id' }, function() {
this.route('index', {path: '/'});
this.route('detail');
});
});
});
App.FilesController = Em.ArrayController.extend();
App.FilesFileController = Em.ObjectController.extend();
App.Person = Ember.Object.extend({});
App.IndexRoute = Ember.Route.extend({
model: function(params, transition){
return new Ember.RSVP.Promise(function(resolve){
Ember.run.later(function(){
var model = App.Person.create();
resolve(model);
}, 3000);
});
}
});
App.LoadingRoute = Em.Route.extend({
renderTemplate: function() {
this.render('loading', {
into: 'application',
outlet: 'loading'
});
}
});
App.FileLoadingRoute = App.LoadingRoute.extend();
App.FilesRoute = Em.Route.extend({
model: function() {
var selfie = this;
return new Ember.RSVP.Promise(function(resolve){
Ember.run.later(function() {
var model = selfie.store.find('file');
resolve(model);
}, 800);
});
}
});
App.FilesIndexRoute = Em.Route.extend({
model: function(){
return this.store.all('file');
}
});
App.FileRoute = Em.Route.extend({
model: function(params) {
return this.store.find('file', params.file_id);
}
});
App.FileIndexRoute = Em.Route.extend({
model: function() {
return this.modelFor('file');
},
renderTemplate: function() {
this.render('files/index', {
into: 'application'
});
this.render('file/index', {
into: 'files/index',
outlet: 'file'
});
}
});
App.FileDetailRoute = Em.Route.extend({
model: function() {
var selfie = this;
return new Ember.RSVP.Promise(function(resolve){
Ember.run.later(function(){
var file = selfie.modelFor('file');
var model = selfie.store.find('fileDetail', file.id);
resolve(model);
}, 800);
});
},
renderTemplate: function() {
this.render('files/index', {
into: 'application'
});
this.render('file/index', {
into: 'files/index',
outlet: 'file'
});
this.render('file/detail', {
into: 'file/index',
outlet: 'detail'
});
},
actions: {
loading: function() {
return true;
}
}
});
App.RlLoadIndicatorComponent = Em.Component.extend({
classNames: ['rl-load-indicator'],
classNameBindings: ['isLoading:rl-overlay:rl-silent'],
overlay: true,
spinner: true,
message: 'Loading...',
loading: false,
isLoading: function() {
return this.get('loading');
}.property('loading'),
spinnerClass: function() {
if (this.get('loading')) {
if (this.get('spinner')) {
return 'rl-spinner';
}
}
return "";
}.property(),
actions: {
setLoading: function() {
this.set('loading', true);
},
setDone: function() {
this.set('loading', false);
}
}
});
App.ApplicationAdapter = DS.FixtureAdapter.extend();
App.File = DS.Model.extend({
name: DS.attr('string'),
text: DS.attr('string'),
detail: DS.belongsTo('fileDetail', {async: true})
});
App.FileDetail = DS.Model.extend({
owner: DS.attr('string'),
canEdit: DS.attr('bool'),
file: DS.belongsTo('file'),
property1: DS.attr('string'),
property2: DS.attr('string'),
property3: DS.attr('string'),
property4: DS.attr('string'),
property5: DS.attr('string')
});
App.File.FIXTURES = [
{id: 1, name: 'File 1', text: 'Blah 1', detail: 1},
{id: 2, name: 'File 2', text: 'Blah 2', detail: 2},
{id: 3, name: 'File 3', text: 'Blah 3', detail: 3},
{id: 4, name: 'File 4', text: 'Blah 4', detail: 4},
{id: 5, name: 'File 5', text: 'Blah 5', detail: 5},
{id: 6, name: 'File 6', text: 'Blah 6', detail: 6},
{id: 7, name: 'File 7', text: 'Blah 7', detail: 7},
{id: 8, name: 'File 8', text: 'Blah 8', detail: 8},
{id: 9, name: 'File 9', text: 'Blah 9', detail: 9},
{id: 10, name: 'File 10', text: 'Blah 10', detail: 10}
];
App.FileDetail.FIXTURES = [
{
id: 1,
owner: 'Spiderman',
canEdit: true,
file_id: 1,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'With great values, comes great bindings'
},
{
id: 2,
owner: 'Iron Man',
canEdit: true,
file_id: 2,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
},
{
id: 3,
owner: 'Thor',
canEdit: false,
file_id: 3,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
},
{
id: 4,
owner: 'Captain America',
canEdit: false,
file_id: 4,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
},
{
id: 5,
owner: 'Neil DeGrasse Tyson',
canEdit: true,
file_id: 5,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
},
{
id: 6,
owner: 'Dr. Doom',
canEdit: false,
file_id: 6,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
},
{
id: 7,
owner: 'Reed Richards',
canEdit: true,
file_id: 7,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
},
{
id: 8,
owner: 'Walter White',
canEdit: true,
file_id: 8,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Say My Name!'
},
{
id: 9,
owner: 'Jesse Pinkmann',
canEdit: true,
file_id: 9,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Bitch'
},
{
id: 10,
owner: 'Hawk Barton',
canEdit: false,
file_id: 10,
property1: 'Value 1',
property2: 'Value 2',
property3: 'Value 3',
property4: 'Value 4',
property5: 'Another Value'
}
];
/* Put your CSS here */
html, body {
margin: 20px;
}
.rl-load-indicator {
text-align: center;
}
.rl-overlay {
position:fixed;
top:0;
left:0;
right:0;
bottom:0;
background-color:rgba(0, 0, 0, 0.85);
background: url(data:;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAABl0RVh0U29mdHdhcmUAUGFpbnQuTkVUIHYzLjUuNUmK/OAAAAATSURBVBhXY2RgYNgHxGAAYuwDAA78AjwwRoQYAAAAAElFTkSuQmCC) repeat scroll transparent\9; /* ie fallback png background image */
z-index:9999;
color:white;
}
.rl-silent {
display: none;
visibility: hidden;
}
.rl-spinner {
width: 30px;
height: 30px;
background-color: #27ae60;
margin: 100px auto;
margin-bottom: 8px;
-webkit-animation: rotateplane 1.2s infinite ease-in-out;
animation: rotateplane 1.2s infinite ease-in-out;
}
.arrow-right {
width: 0;
height: 0;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid green;
}
#-webkit-keyframes rotateplane {
0% { -webkit-transform: perspective(120px) }
50% { -webkit-transform: perspective(120px) rotateY(180deg) }
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }
}
#keyframes rotateplane {
0% {
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)
} 50% {
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)
} 100% {
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="description" content="Loading Thingy" />
<meta charset="utf-8">
<title>Ember Starter Kit</title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.3.0.js"></script>
<script src="http://builds.emberjs.com/tags/v1.7.0/ember.js"></script>
<script src="http://builds.emberjs.com/beta/ember-data.js"></script>
</head>
<body>
<script type="text/x-handlebars">
<h1>{{unbound App.displayName}}</h1>
{{partial "menu"}}
<hr />
{{outlet}}
{{outlet "loading"}}
</script>
<script type="text/x-handlebars" data-template-name="loading">
{{rl-load-indicator loading=true}}
</script>
<script type="text/x-handlebars" data-template-name="_menu">
{{#link-to 'index'}}Home{{/link-to}} | {{#link-to 'files.index'}}Files{{/link-to}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<h3>Index</h3>
Content goes here
</script>
<script type="text/x-handlebars" data-template-name="files/index">
<h3>Files</h3>
<table class="table table-hover">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th> </th>
</tr>
</thead>
<tbody>
{{#each file in model}}
<tr>
<td>{{file.id}}</td>
<td>{{file.name}}</td>
<td>
{{#link-to 'file.index' file}}
<p class="arrow-right"></p>
{{/link-to}}
</td>
</tr>
{{/each}}
</tbody>
</table>
{{outlet "file"}}
</script>
<script type="text/x-handlebars" data-template-name="file/index">
<h3>{{name}}</h3>
{{text}}
<hr />{{#link-to 'file.detail'}}Detail{{/link-to}}
{{outlet "detail"}}
</script>
<script type="text/x-handlebars" data-template-name="file/detail">
<h5>Details</h5>
<hr />
<ul>
<li>owner: {{owner}}</li>
<li>can edit: {{canEdit}}</li>
<li>property 1: {{property1}}</li>
<li>property 2: {{property3}}</li>
<li>property 3: {{property3}}</li>
<li>property 4: {{property4}}</li>
<li>property 5: {{property5}}</li>
</script>
<script type="text/x-handlebars" data-template-name="components/rl-load-indicator">
<div {{bind-attr class=spinnerClass}}></div>
{{unbound message}}
</script>
</body>
</html>
Just create a different resource below the application route, and do all of your loading there. Don't use the index route though, it is only hit when you hit the root of a particular resource (App.IndexRoute would be when you just hit the root of your application).
App = Ember.Application.create();
App.Router.map(function() {
this.resource("top",function(){ // a place you can grab things for the app and block
this.resource('home'); // a place you want to get when everything is ready
});
});
App.ApplicationRoute = Ember.Route.extend();
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo("home");
}
});
App.TopRoute = Ember.Route.extend({
// This does trigger a loading state
model: function(params){
return new Ember.RSVP.Promise(function(resolve){
setTimeout(function(){
resolve();
}, 3000); // 3 second delay, wooh, your server is slow!!!
});
}
});
http://jsbin.com/mivul/edit?html,js,output

How do I load a fixture into a template with a different model in ember?

The intent of my code is to be able to load various fixtures into a template. For example:
The family template:
{{#each model as family}}
<p>{{family.name}} + "is" + {{family.age}} + "years old"</p>
{{/each}}
The brothers fixture: [{ id:1, name:"Greg", age:40 }]
The sisters fixture: [{ id:1, name:"Mary", age:35 }]
So that when I call:
#/brothers I'd get <p>Greg is 40 years old</p>
vs
#/sisters I'd get <p>Mary is 35 years old</p>
I figure I'm having trouble with 1) the correct routing. 2) usage of {{each}}/{{with}}. 3) usage of fixtures/models. You can find EVERYTHING at my github repo. Thanks in advance for the help!
Application Template - application.hbs:
<br><br>
<div class="container">
<ul class="nav nav-pills" role="tablist">
<li class="active">Home</li>
<li>Brothers</li>
<li>Sisters</li>
</ul>
<div class="container">
{{outlet}}
</div>
</div>
Family template (to go into {{outlet}} of application) - family.hbs:
<h1>Fixtures and Models</h1>
{{#each in model as family}}
<p>{{family.name}} is here</p>
{{else}}
<li>DIDN'T WORK</li>
{{/each}}
Family models and fixtures - family.js:
App.Family = DS.Model.extend({
name : DS.attr(),
age : DS.attr()
});
App.Brothers = DS.Model.extend({
name : DS.attr(),
age : DS.attr()
});
App.Sisters = DS.Model.extend({
name : DS.attr(),
age : DS.attr()
});
App.Brothers.FIXTURES = [
{
"id" : 1,
"name" : "Greg",
"age" : 10
},
{
"id" : 2,
"name" : "Mike",
"age" : 23
}
];
App.Sisters.FIXTURES =
[
{
"id" :1,
"name" :"Mary",
"age" :15
},
{
"id" :2,
"name" :"Gina",
"age" :34
}
];
My app.js file for all the routes:
App = Ember.Application.create({
LOG_TRANSITIONS: true
});
App.Router.map(function() {
this.resource('application');
this.resource('home');
this.resource('brothers');
this.resource('sisters');
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('application');
}
});
App.FamilyRouter = Ember.Route.extend({
});
App.HomeRoute = Ember.Route.extend({
});
App.FamilyRoute = Ember.Route.extend({
});
App.BrothersRoute = Ember.Route.extend({
model: function() {
this.store.find('brothers');
},
renderTemplate: function() {
return this.render('family');
}
});
App.SistersRoute = Ember.Route.extend({
model: function() {
return this.store.find('sisters');
}
});
Again, you can find all the codez here at my github repo
You need two fixes.
First, you're using wrong #each syntax. Change it to this:
<h1>Fixtures and Models</h1>
{{#each family in model}}
<p>{{family.name}} is here</p>
{{else}}
<li>DIDN'T WORK</li>
{{/each}}
Second, you're not returning brothers models. Change to:
App.BrothersRoute = Ember.Route.extend({
model: function() {
return this.store.find('brothers');
},
templateName: 'family'
});

Emberjs maximum call stack when displaying hasMany

I'm new to Ember and i have problem with display hasMany relation.
My Models:
App.Shop = DS.Model.extend({
name: DS.attr('string'),
openSettings: DS.hasMany('App.OpenSetting')
});
App.OpenSetting = DS.Model.extend({
title: DS.attr('string'),
data: DS.attr('string'),
shopId: DS.belongsTo('App.Shop')
});
I have mapping:
DS.RESTAdapter.map('App.Shop', {
openSettings: { key: 'openSettings' }
});
DS.RESTAdapter.map('App.OpenSetting', {
shopId: { key: 'shopId' }
});
In index.html in script i have:
{{#each model}}
{{id}} - {{name}} #
{{#each openSettings}}
{{title}}
{{/each}}
{{/each}}
But when object Shop has some relations in openSettings (openSettings:[1,2]) then i get error:
Uncaught RangeError: Maximum call stack size exceeded
What i'm doing wrong?
Fixtures:
App.Shop.FIXTURES = [
{
name: "Supermarket",
id: 2,
openSettings: [
2, 5
]
}
];
App.OpenSetting.FIXTURES = [
{
title: "monday - friday",
data: "8:00 - 24:00",
id: 2,
shopId: 2
},
{
title: "saturday",
data: "8:00 - 1:00",
id: 5,
shopId: 2
}
];
Thanks for help.
Ember throws that error when field is named "data". After change, all works fine.

Error _create while rendering belongsTo children in emberjs

I'm trying to render mediaitems in my post template, but I'm getting this nasty console error:
Uncaught TypeError: Object photo has no method '_create'
These are my models & fixture data:
/**************************
* Models
**************************/
App.Store = DS.Store.extend({
revision: 11,
adapter: 'DS.FixtureAdapter'
});
App.Mediaitem = DS.Model.extend({
type: DS.attr('string'),
url: DS.attr('string'),
post: DS.belongsTo('App.Post')
});
App.Post = DS.Model.extend({
type: DS.attr('string'),
title: DS.attr('string'),
summary: DS.attr('string'),
body: DS.attr('string'),
date: DS.attr('date'),
mediaitems: DS.hasMany('App.Mediaitem', {embedded:true})
});
App.Post.FIXTURES = [
{
id:"post-one",
type:"news",
title:"First Post",
summary:"Ipsum Lorem",
date:"2013-02-07T16:44:57",
mediaitems:[{
id:593,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
},
{
id:789,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
}]
},
{
id:"post-two",
type:"gallery",
title:"Second Post",
summary:"Lorem ipsum",
date:"2013-02-07T16:44:57",
mediaitems:[{
id:342,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
},
{
id:231,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
}]
}
];
This is my template code:
<script type="text/x-handlebars" data-template-name="post">
<div class="detail">
{{#linkTo posts}}close{{/linkTo}}<br/>
<h2>{{id}} - {{title}}</h2>
<br/>
{{#each mediaitem in mediaitems}}
print something
{{/each}}
</div>
</script>
Can someone help me out?
The FIXTURE adapter does not support embedded relationships, at least not in rev 11.
You need each model to have its own FIXTURE definition with the record and the relationships to have the id/s of the proper child/parent.
App.Post.FIXTURES = [
{
id:"post-one",
type:"news",
title:"First Post",
summary:"Ipsum Lorem",
date:"2013-02-07T16:44:57",
mediaitems:['593','789']
},
{
id:"post-two",
type:"gallery",
title:"Second Post",
summary:"Lorem ipsum",
date:"2013-02-07T16:44:57",
mediaitems:['342','231']
}];
App.Mediaitems.FIXTURES = [{
id:342,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
},
{
id:231,
post_id:"post-two",
type:'photo',
url:'http://www.google.com'
},
{
id:593,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
},
{
id:789,
post_id:"post-one",
type:'photo',
url:'http://www.google.com'
}];