Getting data from DS.PromiseArray in EmberJS - ember.js

I'm new to emberJS and I'm having some trouble working with promises.
Here is my router:
this.resource('menus', function(){
this.resource('menu', {path: '/:menu_id'}, function(){
this.resource('submodule', {path: '/:submodule_id'});
});
});
});
I have nested routes, and the child route returns a menuss object based on a given id.
Here is my MenuRoute:
App.MenuRoute = Ember.Route.extend({
model: function(params){
return this.store.find('menuss', params.menu_id);
}
});
Here are my models:
App.Menuss = DS.Model.extend({
name: DS.attr('string'),
subModule: DS.hasMany('submodule', {async:true})
});
App.Submodule = DS.Model.extend({
name: DS.attr('string'),
content: DS.attr('string')
});
The 'subModule' attribute of Menuss model contains an array of Submodule model id's.
Inside my menu template, I'm receiving a menuss object and I want to display the SubModules each menu item has.
However, when I call {{this.subModule}}, it returns <DS.PromiseArray:ember488>. How can I get the contents from this subModule array?
I looked at some similar questions where they say use the then() method, but I can't seem to figure it out here.

In the template you'll want to iterate the property since it's an array, ember/handlebars will deal with the synchronicity of the PromiseArray.
{{#each item in subModule}}
{{item.name}}
{{/each}}

Related

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.

Unexpected text being rendered by Ember

I have models
// models/group
export default DS.Model.extend({
parent: DS.belongsTo('parent'),
items: DS.hasMany('item', {async: true}),
quantity: Ember.computed.sum('items.#each.quantity'),
});
// models/item
export default DS.Model.extend({
...
quantity: DS.attr('number')
});
And in my template (with controller.model set to parent) I try to render
{{#each group}}
{{quantity}}
{{/each}}
and expect a list of numbers, but instead what's rendered is a list of text like <spa#model:item::ember1036:165>
I'm guessing that the async promise is only resolved after rendering, but then why does it not update?
I don't believe sum will pull properties from each item in a collection. I believe it has to be a collection of numbers.
quantities: function(){
return this.get('items').getEach('quantity');
}.property('items.#each.quantity'),
quantity: Ember.computed.sum('quantities'),

Ember.js - setupController model no output

Ey guys,
I have a strange problem with one of my models:
The following code is responsible for getting the page model and all the new projects.
Bouwbedrijf.ProjectsOldRoute = Ember.Route.extend({
model: function() {
return App.Page.find(3);
},
setupController: function(controller, model)
{
controller.set('content', model);
controller.set('projecten', App.OldProjects.find());
},
renderTemplate: function (){
this.render();
this.render('pagetitle', {into: 'projects', outlet: 'page-title'});
this.render('oldprojectshowcase', {
into: 'projects/old',
outlet: 'projecten'
});
}
});
However if I loop through the controller.projecten within the template there is no propery output. I do see 3 li elements rendered but I can't seem to display the name of a project...
Here is the template code
<script type="text/x-handlebars" data-template-name="oldprojectshowcase">
<h3>Projects showcase</h3>
<ul>
{{#each project in projecten}}
<li>{{project.name}}</li>
{{/each}}
</ul>
</script>
To make things more clear for you guys I prepared a jsbin -> http://jsbin.com/Uqop/2/
Within this example there is a page Old projects which is displayin a showcase (sort of ;) )
There is no relation between the problem and setupController.
The problem is you are trying to access a property which you have not defined in the model.
The property name is not defined in the App.OldProjects model.
Defining it does the trick.
App.OldProjects = DS.Model.extend({
title: DS.attr('string'),
project: DS.attr('string'),
name: DS.attr('string'),
img: DS.attr('string')
});
Corrections to your JSBin.

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";
}
})
})

Ember.js Router v2 dynamic slug

In the following example, using the new Router v2 API, the ember application behaves as expected with one exception. When hovering over the dynamically created links, using a registered #linkTo Handlebars the url shows undefined.
How do I have a slug field in the URL?
Here is the model
App.Todo = DS.Model.extend({
slug: DS.attr('string'),
date: DS.attr('date'),
updated: DS.attr('date'),
task: DS.attr('string'),
description: DS.attr('string')
});
My Router
App.Router.map(function(match){
this.route('index', {path: '/'});
this.resource('todos', {path: '/todos'}, function(){
this.resource('create', {path: '/create'});
this.resource('todo', {path: '/:slug'}, function(){
this.resource('edit', {path: 'edit'});
});
});
});
I know that this does show 'undefined', but this would be a nice (Handlebars)
{{#each todo in tasks}}
<div class="user">
{{#linkTo todo todo.slug}}<h4><i class="icon-list"></i>{{todo.task}}</h4>{{/linkTo}}
<p>{{todo.description}}</p>
</div>
{{/each}}
Thanks for any pointers! I'm using Ember-data also
Here is a example fiddle
http://jsfiddle.net/R2SPs/6/
This works for ember routing v2.1 (01.16.13)
Thanks to rakl on #emberjs on IRC here is a mixin that solves the problem
App.SlugRouter = Ember.Mixin.create({
serialize: function(model, params) {
var name, object;
object = {};
name = params[0];
object[name] = model.get('slug');
return object;
}
});
Now just place that in your Router and your golden
App.TodoRoute = Ember.Route.extend(App.SlugRouter,{
//insert your code
});
The path of the route is "todo.index" with the resource definition:
this.resource('todo', {path: '/:slug'}, ...
So create Route and Controller for it.