I wonder how to get the param (the ID) of my edit route in Ember.js.
That's how I defined my route:
this.resource('accounting', function() {
this.resource('accounting.requests', { path: '/requests' }, function() {
this.route('new');
this.route('archived');
});
this.resource('accounting.request', { path: '/request/:request_id' }, function() {
this.route('edit');
});
});
Now I want to fetch the model by its ID on this edit route /accounting/request/3/edit:
App.AccountingRequestEditRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('request', params.request_id);
}
});
But this doesn't work because params is empty.
This works as expected, but the edit route doesn't:
App.AccountingRequestRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('request', params.request_id);
}
});
When you are in a child route you can use this.modelFor, example:
App.AccountingRequestEditRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('request');
}
});
Because in order to go to request.edit, you have to provide an id or object to its parent resource, request either directly going to the route passing the url to the browser or indirectly by transition from other routes that happen to link to edit.
Related
Let's say that I want to have URLs like /users/JoshSmith for maximum readability/shareability.
I set up my Router:
this.resource('user', path: '/users/:username')
And my route:
var UserRoute = Ember.Route.extend({
model: function(params) {
debugger
return this.store.find('user', { username: params.username });
}
});
But this findQuery function actually returns an array, since it's calling /users?username= instead of calling /users/:username like I would normally do.
I'm a little lost as to how I should be handling this; I'm assuming there's a convention out there, I just can't find it.
As suggested here: http://discuss.emberjs.com/t/find-by-different-property/2479
Just override serialize on your route.
var UserRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('user', { username: params.username });
},
serialize: function(model) {
return { username: model.get('username') };
}
});
This replaces the default which looks like this:
serialize: function(model) {
// this will make the URL `/posts/12`
return { post_id: model.id };
}
Source: http://emberjs.com/api/classes/Ember.Route.html#method_serialize
I had this same problem as well, findQuery always returns a record array. The way I got around this was to simply change my model hook in the router to
model: function(params) {
return this.store.find('user', { username: params.username }).then(function(users) {
return users.get('firstObject');
});
}
I have a blog route, and a blog-post route.
Router:
App.Router.map(function () {
this.resource('blog', function () {
this.route('post', {path: ':id/:title'});
});
});
Routes:
App.BlogRoute = Ember.Route.extend({
model: function () {
return this.store.find('BlogPost');
}
});
App.BlogPostRoute = Ember.Route.extend({
model: function (params) {
return this.store.findById('BlogPost', params.id);
},
serialize: function (model, params) {
return {
id: model.get('id'),
title: Ember.String.dasherize(model.get('title'))
}
}
});
In my Handlebars template for the parent blog route I have an {{outlet}} that works fine when I click one of the {{#link-to}}s.
What I want to do is render by default the most recent (highest ID) blog post when a user goes to the /blog route.
I found this question and tried this as a result, to no avail:
App.BlogIndexRoute = Ember.Route.extend({
redirect: function () {
var latest = 3;
this.transitionTo('blog.post', {id: latest});
}
});
(latest is just a placeholder for this.model.pop() or whatever it needs to be.)
I just can't figure out how exactly to load the sub route with the data from the model.
You can fetch the model for any resource/route that has already been fetched (aka parent resources) using modelFor
App.BlogIndexRoute = Ember.Route.extend({
redirect: function () {
var blogs = this.modelFor('blog');
if(blogs.get('length')){
this.transitionTo('blog.post', blogs.get('firstObject')); // or blogs.findBy('id', 123)
}
}
});
I got the following code:
App.ApplicationSerializer = DS.ActiveModelSerializer.extend({});
App.Router.map(function(){
this.resource('clients', { path : '/' });
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api'
});
App.ClientsRoute = Ember.Route.extend({
setupController: function(controller, model){
controller.set('model', model);
this.controllerFor('patients').set('model', this.store.find('patient'));
}
});
When the main page is loaded a request is sent only to localhost:3000/api/patients and not to clients which is the main controller for the given view :/
Can you spot the mistake? I am using App.ApplicationSerializer = DS.ActiveModelSerializer.extend({});
I thought that might be the error, but after removing it I saw no changes at all.
You are not defining the model for ClientsRoute:
App.ClientsRoute = Ember.Route.extend({
model: function() {
return this.store.find('client');
}
});
The only case where its not necessary to define the model, is when the route is a simple dynamic segment (show a specific record). Example:
App.Router.map(function() {
this.route('client', { path: '/clients/:client_id' });
});
App.ClientRoute = Ember.Route.extend({
// Default model (no need to explicitly define it):
// model: function(params) {
// return this.store.find('client', params.client_id);
// }
});
Given the following Ember.js application (using Ember 1.0.0.rc.6.1 and Ember Data 0.13):
App = Ember.Application.create({ LOG_TRANSITIONS: true });
App.Store = DS.Store.extend();
App.Router.map(function() {
this.resource('promotions', function() {
this.resource('promotion', { path: '/:promotion_id' }, function() {
this.resource('entrants', function() {
this.resource('entrant', { path: '/:entrant_id' });
});
});
});
});
App.PromotionRoute = Ember.Route.extend({
model: function() {
return { id: 1, name: 'My Promotion' };
}
});
App.EntrantsIndexRoute = Ember.Route.extend({
model: function(params) {
console.warn('EntrantsIndexRoute', '\nparams:', params, '\nparams.promotion_id:', params.promotion_id, '\narguments:', arguments);
console.log('params should be:', { promotion_id: 1 });
console.log('The queried URL should be:', '/entrants?promotion_id=1');
return App.Entrant.find({promotion_id: params.promotion_id});
}
});
App.Entrant = DS.Model.extend({
name: DS.attr('string')
});
If you enter the url #/promotions/1/entrants, which should be a nested resource, the params is an empty object. How can I access promotion_id there? JSFiddle here, take a look at the console after clicking on "Click me": http://jsfiddle.net/Kerrick/4GufZ/
While you can't access the dynamic segments of the parent route, you still can retrieve the model for the parent route and get its ID, like this:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
var promotion_id = this.modelFor('promotion').id;
return App.Entrant.find({ promotion_id: promotion_id });
}
});
Or, if there is a has-many relation between promotion and entrants, you even might do:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
return this.modelFor('promotion').get('entrants');
}
});
Try this code:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
var promotion_id = this.modelFor('promotion').query.promotion_id;
return App.Entrant.find({ promotion_id: promotion_id });
}
});
I have the following route structure
App.Router.map(function(match) {
this.route("days", { path: "/" });
this.resource("day", { path: "/:day_id" }, function() {
this.resource("appointment", { path: "/appointment" }, function() {
this.route("edit", { path: "/edit" });
});
});
});
When I'm inside the AppointmentIndexRoute I'm looking for a way to create a new model using some meta day from the day (parent) model but because the day model does not yet know about this appointment I'm unsure how to associate them until the appointment is created / and the commit is fired off.
Any help would be much appreciated
From within the AppointmentIndexRoute's model hook you can use modelFor('day') to access the parent model. For example:
App.AppointmentIndexRoute = Ember.Route.extend({
model: function(params) {
day = this.modelFor("day");
...
}
});
Another example is here: emberjs 1.0.0pre4 how do you pass a context object to a resource "...Index" route?
What if I am not using ember data? How do I get the parent id in a route like
this.resource('workspace',function () {
this.resource('workflow', {path: '/:workspace_id/workflow'}, function () {
this.route('show', {path: '/:workflow_id'});
});
});
This code will not work:
App.WorkflowShowRoute = Em.Route.extend({
model: function(params) {
var ws = this.modelFor('workspace'); //ws is undefined
return this.store.find('workflow', params.id, ws.id);
}
});
EDIT:
I found a workaround, it's not ideal but works exactly the way I want it.
this.resource('workspace',function () {
this.route('new');
this.route('show', {path: '/:workspace_id'});
//workflow routes
this.resource('workflow', {path: '/'}, function () {
this.route('new', {path:'/:workspace_id/workflow/new'});
this.route('show', {path: '/:workspace_id/workflow/:workflow_id'});
});
});
And in my workflow route, I can access the workspace_id jus as I expect from the params property:
App.WorkflowShowRoute = Em.Route.extend({
model: function(params) {
return this.store.find('workflow', params.workflow_id, params.workspace_id);
}
});
Finally, here is my link-to inside the workspace.show route helper:
{{#each workflow in workflows}}
<li>
{{#link-to 'workflow.show' this.id workflow.id}}{{workflow.name}}{{/link-to}}
</li>
{{/each}}