Ember.js Router v2 dynamic slug - ember.js

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.

Related

Ember How can i render a child route into his parent?

I'm new with Ember and trying to render the content into the category template. So, if I clicked on the category, it will show me details and list content in the category template. I have tested something, but it didn't work. I have searched for this problem, but I can't solve it. I hope you can help me.
best regards
app.js
TableNotices.Router.map(function() {
this.resource('tableNotices', { path: '/' }, function(){
this.resource('category', {path: ':id'}, function(){
this.route('contents');
this.resource('content', {path: '/content/:id'});
});
});
});
TableNotices.ContentsRoute = Ember.Route.extend({
model: function() {
return this.modelFor('category').get('contents');
}
});
TableNotices.Content = DS.Model.extend({
content: DS.attr('string'),
contentType: DS.attr('string'),
orderPos: DS.attr('number'),
category: DS.belongsTo('category')
});
TableNotices.Category = DS.Model.extend({
name: DS.attr('string'),
parent: DS.attr('number'),
picture: DS.attr('string'),
contents: DS.hasMany('content', {async:true})
});
index.html:
<script type="text/x-handlebars" data-template-name="category">
{{name}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="contents">
foobar
</script>
jsbin
In the route you can specify how to render the templates with renderTemplate.
TableNotices.ContentsRoute = Ember.Route.extend({
model: function() {
return this.modelFor('category').get('contents');
}
renderTemplate: function() {
this.render('contents', { // the template to render
into: 'category', // the template to render into
outlet: 'category', // the name of the outlet in that template
controller: 'contents' // the controller to use for the template
});
}
});
<script type="text/x-handlebars" data-template-name="category">
{{name}}
{{outlet "contents"}}
</script>
Although Aaron Renoir's answer will work, the best way to think of this is that because your routes are nested, your templates need to be nested as well. Ember will render each of the nested templates into the parent template when these nested routes are activated. This gives you a nice way to delegate different parts of your page to various templates which helps to keep the content organized.
Each of your "parent" templates will need an {{outlet}} for the child templates to be rendered into.

Add second model to a route

My application is for swimming lessons. I need to add swimmers to a class. The relationship is has many in both directions. A Lesson can have many Swimmers and Swimmers can have many Lessons.
From the lesson route, I would like to select a swimmer in a drop down, from a list of all swimmers and have an action add that swimmer's ID to the lesson's "swimmers" array.
I can't get the swimmers to show up in the drop down field because I don't think I am loading the second model correctly.
I would also be open to suggestions of how to add a specific swimmer to a specific class. It's important to see all available swimmers
I am new to both ember and programming so please keep this in mind when making suggestions. Thank you!
App.Router.map(function() {
this.resource('lessons', { path: '/lessons' }, function() {
this.resource('lesson', { path: '/:lesson_id' })
this.route('new', { path: '/new' })
});
this.resource('swimmers', { path: '/swimmers' }, function() {
this.resource('swimmer', { path: '/:swimmer_id' })
this.route('new', { path: '/new' })
});
});
App.Lesson = DS.Model.extend({
type: DS.attr(),
name: DS.attr(),
/*level: DS.attr(), sometimes there are hybrid levels, likely leave it up to */
instructor:DS.belongsTo('instructor', {async: true}),
startDate: DS.attr(),
endDate: DS.attr(),
capacity: DS.attr('number'),
swimmers: DS.hasMany('swimmer',{async: true}),
});
App.Swimmer = DS.Model.extend({
nameFirst: DS.attr(),
nameLast: DS.attr(),
level: DS.attr(),
birthdate: DS.attr(),
gender: DS.attr(),
note:DS.attr(),
lessons: DS.hasMany('lesson', {async: true}),
});
App.LessonRoute = Ember.Route.extend({
model: function(params) {
return Ember.RSVP.hash({
lesson: this.store.find('lesson', params.lesson_id),
swimmers: this.store.findAll('swimmer')
})
},
setupController: function(controller, model) {
controller.set('model', model.lesson);
controller.set('swimmer', model.swimmer);
},
});
Drop down I am trying to use
<div class="form-group">
<label for="lesson_swimmers" class="col-sm-2 control- label">Swimmers</label>
<div class="col-sm-9">
{{view Ember.Select content=swimmers optionLabelPath="content.fullName" class="form-control" id="lesson_swimmers"}}
</div>
</div>
There are two answers to this question. The right one for you will depend on how you are providing the Model.
If you are arriving via transferTo or linkTo you will need to use a different approach than if you are arriving directly via URL.
#Kingpin2k answers the question and provides examples here,
Kingpin2k's elegant solution.

Filling Ember selection with data received from server

I would like to receive json data from server and then generate html selection tag in Ember. This is my handlebars template:
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="rankings">
{{view Ember.Select contentBinding="countries" optionLabelPath="countries.name" optionValuePath="countries.path"}}
</script>
and my Ember trunk
App.ApplicationAdapter = DS.RESTAdapter;
App.Router.map(function() {
this.route('rankings')
});
App.RankingsRoute = Ember.Route.extend({
setupController: function(controller, model) {
controller.set('countries', this.store.findAll('country'));
}
});
App.RankingsController = Ember.Controller.extend({
countries: []
});
App.Country = DS.Model.extend({
path: DS.attr('string'),
name: DS.attr('string'),
}
It is not working fine. I am not having any errors in console and template is not rendering with this route and controller. What can be wrong?
Ember.Select looks for data on your controller's model. You have the countries array set up outside of your content, so it will not be able to view the data.
Personally, I would do it in the following way, though there are a couple of different approaches you can take to get similar results:
App.ApplicationAdapter = DS.RESTAdapter;
App.Router.map(function() {
this.route('rankings')
});
App.RankingsRoute = Ember.Route.extend({
model: function() {
return {countries : this.store.findAll('country')};
}
});
App.RankingsController = Ember.Controller.extend({
});
App.Country = DS.Model.extend({
path: DS.attr('string'),
name: DS.attr('string'),
}

Getting data from DS.PromiseArray in EmberJS

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}}

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