Ember app won't load data from has_many relationships using ActiveModelAdapter - ember.js

This app works fine when the store is FixtureAdapter, but will not load has_many relationships when the store is ActiveModelAdapter.
The Route is like this:
App.IndexRoute = Ember.Route.extend({
model: function(){
return this.store.find('post', 1 )
}
});
The models are like this:
App.Post = DS.Model.extend({
name: DS.attr('string'),
description: DS.attr('string'),
comments: DS.hasMany('comments', {embedded: 'always'})
});
App.Comment = DS.Model.extend({
text: DS.attr('string'),
post: DS.belongsTo('post')
});
The handlebars template calls for:
{{name}}
{{#each comments}}
{{text}}
{{/each}}
The name appears, the comments do not.
In the ember developer console, the comments are not getting loaded at all.
The server seems to be serving the serialized content correctly (as far as I can tell). It looks like this:
{"post":{"id":1,"name":"Title","description":"Lorem Ipsum","comments":[{"id":1, "text": "commentary here"}]}}
Does anyone know why this isn't working and how I could fix it? I've been struggling with this for hours now and cannot figure out why it's not working. Thanks very much for any insight you can provide.
I'm using this as part of a Rails project, and these are the relevant gems:
gem 'ember-rails'
gem 'ember-source', '1.3.0'
gem 'ember-data-source', '~> 1.0.0.beta.6'
gem "active_model_serializers"

You need to specify a custom adapter for each over-riden model and mixin the Embedded Records Mixin:
App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
comments: {embedded: 'always'}
}
});
Please see the comments in the Ember-Data source code for more info.

Related

Ember can't get data from hasMany relationship

I try to build Rails+Ember app using Ember data.
Model:
export default DS.Model.extend({
name: DS.attr('string'),
content: DS.attr('string'),
image_before: DS.attr('string'),
created_at: DS.attr('date'),
updated_at: DS.attr('date'),
status: DS.attr('number'),
comments: DS.hasMany('comment', {async: true}),
user: DS.belongsTo('user'),
});
and get json like this (json is generated with active_model_serializers)
{"work":{
"id":3,
"user_id":1,
"content":"My first photo",
"image_before": "image_before/original/AnViWyuup5I.png",
"created_at":"2015-08-11T16:57:24.153Z",
"updated_at":"2015-11-13T11:39:44.076Z",
"status":1,
"comment_ids":[13]
},
"comments": [{
"id": 13,
"text": "good!",
"created_at": "2015-09-28T10:34:16.461Z",
"user_id": 2
}]
}
Template is:
<div class="work__img-wrapper">
<img class="work__img" src="{{model.image_before}}">
</div>
<div class="work__content">{{model.content}}</div>
<div class="work__comments-list">
<strong>Comments( {{model.comments.length}} ):</strong>
{{#each model.comments as |comment|}}
<div class="work__comment">
<div class="work__comment-text">{{comment.text}}</div>
</div>
{{/each}}
</div>
At page, I get all information about work and Comments( 0 ), but Ember Inspector at Chrome shows comment.
How i can print comments too?
Your model definition should read:
comments: DS.hasMany('comment', {async: false}),
because the related data is being side-loaded with the response, not being fetched asynchronously.
If this is an Ember 2.0 application, the default async setting is true. From the Ember Blog (http://emberjs.com/blog/2015/06/18/ember-data-1-13-released.html, emphasis mine):
In Ember Data 2.0 relationships will be asynchronous by default. Sync
relationships will still be supported but you will need to manually
opt into them by setting { async: false } on your relationships. Ember
Data 1.13 will log a deprecation warning you if you have any
relationships where the async property is not explicitly set.
Additionally you can use ember-watson to help identify cases in your
codebase where you have relationships without an explicit async
property.
Problem solved. By default, DS.hasMany associated IDs are not added to the objects that are serialized (http://emberjs.com/api/data/classes/DS.EmbeddedRecordsMixin.html).
Should add
export default DS.ActiveModelSerializer
.extend(DS.EmbeddedRecordsMixin)
.extend({
attrs: {
comments: {serialize: 'ids', deserialize: 'ids'}
}
});

How to sort Ember Data model output?

I've searched and searched, but all the examples seem either outdated, aren't in the file structure enforced by Ember CLI, etc.
Anyway, say I have a model in app/models/employee.js:
export default DS.Model.extend({
firstname: DS.attr('string'),
lastname: DS.attr('string'),
});
And a route in app/routes/employees.js:
export default Ember.Route.extend({
model: function() { return this.store.findAll('employee'); },
});
And a template in app/routes/employees.hbs:
{{#each model as |employee|}}
<tr><td>{{employee.firstname}}</td><td>{{employee.lastname}}</td></tr>
{{/each}}
What do I need to add to sort that table by firstname, for example?
I gather I'm supposed to use Ember.computed.sort(), something like:
sortedEmployee: Ember.computed.sort('employees', ['firstname'])
And then do {{#each sortedEmployee as ...}} in the template, but I'm apparently not defining sortedEmployee in the right place.
app/controllers/employees.js
export default Ember.Controller.extend({
sortProperties: ['firstname:asc'],
sortedEmployees: Ember.computed.sort('employees', 'sortProperties')
});
app/routes/employees.hbs:
{{#each sortedEmployees as |employee|}}
{{employee.firstname}}
{{/each}}
Example in JSbin: http://emberjs.jsbin.com/regowa/7/edit?html,css,js,output
You are on the right track, try the following:
sortProperties: ['firstname:asc'], // or just 'firstname', or 'firstname:desc'
sortedEmployee: Ember.computed.sort('employees', 'sortProperties')
I think it's weird to have to define an extra property on the component/controller, but that way it works.

ember.js - ember-cli: ember-data not available on child view

I'm using the latest ember-cli and currently testing it, creating very simple app using ember-data and http-mock for RESTAdapter - ember generate http-mock api-server
Single post get from the API:
http://localhost:4200/api/api-server/posts/1
Result
{"post":
{
"id":1,
"title":"How to write a JavaScript Framework",
"author":"Tomhuda Katzdale",
"body":"Lorem ipsum dolor sit amet"
}
}
Here are all the relevant codes:
Adapters
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
namespace: 'api/api-server'
});
Model
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
author: DS.attr('string'),
body: DS.attr('string')
});
router.js
import Ember from 'ember';
var Router = Ember.Router.extend({
location: EmbercliDataENV.locationType
});
Router.map(function() {
this.route('application');
this.resource('posts', function() {
this.resource('post', { path: ':post_id' });
});
});
export default Router;
Routes (posts and post) - view and child view
posts route
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('post');
}
});
post route
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
});
template
posts.hbs
<h2>Posts List</h2>
<ul>
{{#each}}
<li>
{{#link-to 'post' this}}{{title}}{{/link-to}} | {{author}} | {{body}}
</li>
{{/each}}
</ul>
{{outlet}}
post hbs
<h2>Single Post</h2>
<p>Post title: {{title}}</p>
<p>Post author: {{author}}</p>
<p>Post body: {{body}}</p>
THE PROBLEM: if you look at the screen-cap below, in the chrome ember debugger, the single post model is hooked to the post route but is not printed in the post.hbs
Using just the ember starter kit, I got no problem at all with the exact same app.
Thank you for any help, cheers
UPDATE
The following is the exact same Ember app coded using the starter kit, host in xampp and using PHP Slim framework for REST Api. Working FINE!
try to fix your data, because post is nested in posts, try this:
{"post":[
{
"id":1,
"title":"How to write a JavaScript Framework",
"author":"Tomhuda Katzdale",
"body":"Lorem ipsum dolor sit amet"
}]
}
check within your posts hbs if the data is visible, then post should work fine
After browsing the Ember.js forum I got the answer there - http://discuss.emberjs.com/t/strange-behavior-w-retrieving-model-from-controller/6155
It seems when using the Ember generate controller command, you end up with Ember.Controller, not Ember.ObjectController or Ember.ArrayController lol.
I edit my post controller from: (generate by the Ember generate controller command)
export default Ember.Controller.extend({
});
to
export default Ember.ObjectController.extend({
});
and now the model is binding :D
<h2>Posts List</h2>
<ul>
{{#each}}
<li>
{{#link-to 'post' post}}{{title}}{{/link-to}} | {{author}} | {{body}}
</li>
{{/each}}
</ul>
{{outlet}}
1.instead of 'this' use post, hope this will fix the issue
http://emberjs.com/guides/templates/links/#toc_adding-additional-attributes-on-a-link

duplicated data when navigating without reloading page using ember-data

I'm using ember.js 1.0.0-pre4, ember-data revision 11.
I have the following model:
App.DbProcess = DS.Model.extend({
pid: DS.attr('number'),
backendStart: DS.attr('string'),
transactionStart: DS.attr('string'),
queryStart: DS.attr('string'),
stateChange: DS.attr('string'),
waiting: DS.attr('boolean'),
state: DS.attr('string'),
query: DS.attr('string')
})
With the following route:
App.HomeDbProcessesRoute = Ember.Route.extend({
model: function() {
return App.DbProcess.find();
}
})
I then have a template which uses {{#each controller}}{{/each}} to render all the processes retrieved. However if I navigate to other pages (without reloading the page) and returning back to the processes page, the processes will be retrieved again and the duplicates are rendered on page.
EDIT: I also tried this, but it didn't work:
DS.RESTAdapter.map('App.DbProcess', {
primaryKey: 'pid'
})
I had the same issue now and here is my little hot-fix:
{{#if id}}
<div>
{{title}}
</div>
{{/if}}
In the template I render item from store only if it has id set (only those are coming from databse). But You propably solved it already!
(using revision 12)
Turns out you can do something like this to customize the primary key globally
App.Adapter = DS.RESTAdapter.extend({
url: document.location.protocol+'//url-api.com',
serializer: DS.RESTSerializer.extend({
primaryKey: function(type) {
// If the type is `BlogPost`, this will return
// `blog_post_id`.
var typeString = (''+type).split(".")[1].underscore();
return typeString + "_id";
}
})
})

Rendering nested objects in Ember.js

New to Ember and I cannot figure out how to render nested options either via associated ember-data models or simply as json objects.
JSON looks like this:
contact: {
first_name,
last_name,
emails: [{email1...}, {email2...}]
}
Looking for the easiest solution, I tried this in handlebars template:
{{#each emails}}
...
{{/each}}
Trying a more advanced solution, which will eventually be needed I created the following ember-data models:
App.Contact = DS.Model.extend({
first_name: DS.attr('string'),
last_name: DS.attr('string'),
company: DS.attr('string'),
emails: DS.hasMany('Rainmaker.Email')
});
App.Email = DS.Model.extend({
contact_id: DS.attr('number'),
email_address: DS.attr('string'),
emails: DS.belongsTo('Rainmaker.Contact')
});
Which seems to be working somewhat (App.Email:ember517 renders on the screen) but it looks like it's still trying to ping the server to get the email addresses and I've already got them lazy loaded.
I have no idea where to go next and greatly appreciate any guidance or links to documentation that I've overlooked. Thanks.
On 28. dec the Ember team has included support for embedded records. If you look at https://github.com/emberjs/data at about 1/3 of the page, it gives you some directions on this.
In your case, simply altering emails: DS.hasMany('Rainmaker.Email') to emails: DS.hasMany('Rainmaker.Email',{embedded:true}) should do the trick according to the docs.