I am developing a website using Ember JS.
I have created a nested route like this:
//router
this.resource('store/checkout', {path: '/store/checkout/:order_id'}, function(){
this.resource('store/checkout-lines', {path: ''});
});
This results in the route /store/checkout/:order_id calling both routes and corresponding tempaltes.
The template for store/checkout has an {{outlet}} for the template store/checkout-lines.
In the routes I have this code:
//store/chekout
export default Ember.Route.extend({
model: function(params) {
return this.store.find('order', params.order_id);
}
});
//store/checkout-lines
export default Ember.Route.extend({
model: function(params) {
var order_id = params.order_id; //this does not work
return this.store.find('order-item', {orderId: order_id});
}
});
But my problem is that in the route for store/checkout-lines, I cannot get the orderId.
How can I achieve this? Or am I at the wrong track and should be doing this in another way?
My goal is that the route /store/checkout/:order_id should call the server to fetch both order and orderItems.
What some people seem to miss is that even if you are visiting a nested route, the model for the parent route is loaded. In your nested route, you can easily fetch the model from the parent route using modelFor(type)and then get your information from there. In your case it would be like this.
//store/checkout-lines
export default Ember.Route.extend({
model: function(params) {
var order_id = this.modelFor('checkout').get('id');
return this.store.find('order-item', { orderId: order_id });
}
});
This might seem like an extra step but when you get around to it it really makes a lot of sense and works very well.
Related
I wanted to make a searchQuery that needs to go to the server and fetch new data (the query has to be in the server Filter is not an option)
So I figured out that I must have a different route for search
(using ember_cli)
I have a hbs/controller/route named sessions
And now I added a route search-sessions.js
The search function in the sessions controller calls: this.transitionToRoute("search-sessions", query);
I wanted to not DRY so I tried to make search-sessions.js work with sessions controller/hbs (they are exactly the same other than the fact that they have a query passed to the server)
I tried adding the following code in search-sessions.js route:
export default Ember.Route.extend({
model: function(params) {
return this.store.findQuery('session', params.filters);
},
controllerName: 'sessions',
renderTemplate: function() {
this.render('sessions');
}
});
The thing is - that the model/view doesn't get updated unless I refresh the page
If I duplicate the code (separate hbs/controller for search-sessions it will work but will miss the point of not duplicating code)
The following seems to refresh the model:
App.SearchRoute = Ember.Route.extend({
model: function(params) {
return ['pink', 'orange', 'green'];
},
controllerName: 'common',
renderTemplate: function() {
this.render('common');
}
});
What are you doing different? Can you reproduce your issue in the following jsbin?
http://emberjs.jsbin.com/yukaxe/2/edit
This is part of my router
App.Router.map(function () {
this.resource('report', {path: '/noticia/:report_id'}, function() {
this.route('pictures');
});
});
I have defined an App.ReportPicturesController but my route App.ReportPicturesRoute insists on loading a different controller.
If I do not specify a model hook, it load the App.ReportController, and if I load the model I need (that is called comment) in loads the App.CommentController.
I've tried to set controllerName to reportPictures but it didn't work.
What I have to do to make the route load ReportPicturesController? Why is not loaded the expected controller?
EDIT: If it makes any difference, I'm using ember 1.8.1, ember-data 1.0.0-beta.12, and this is what the route looks like,
App.ReportPicturesRoute = Ember.Route.extend({
model: function(params) {
var report = this.modelFor('report');
return this.store.createRecord('comment', {
inReplyToStatus: report
});
}
});
EDIT2: The full source code is at https://github.com/camolin3/tweetsaster
It is working as expected when I try.. have a look:
http://emberjs.jsbin.com/rayoje/2/
You are missing the ReportRoute model hook implementation similar to this
App.ReportRoute = Ember.Route.extend({
model: function(params) {
return {id:params.report_id};
//or with ember-data return this.store.find('report', params.report_id);
}
});
I have an example route:
this.route('client', {path: ':id'});
I can access this in my route like this:
model: function(params) {
console.log(params.id);
}
How do I access the :id in my controller?
This is how I do it in my application. Not sure if this is the best approach.
App.IndexRoute = Em.Route.extend({
model: function(params) {
this.set('params', params);
},
setupController: function(controller, model) {
controller.set('params', this.get('params'));
this._super(controller, model);
}
});
Alternatively you can also do a lookup on the container inside your controller. But I dont really think this is a good approach. Here is an example.
this.get('container').lookup('router:main').router.currentHandlerInfos
.findBy('name','index').params
There's a serialize function within the Route that you can take advantage of. Here's the API Documentation for it. However, in your context, you can just do this:
App.IndexRoute = Em.Route.extend({
model: function(params) {
console.log(params.client_id);
},
serialize: function(model){
return { client_id : model.id };
}
});
Let me know if this works!
I also noticed an error in your route definition. It should presumably be
this.route('client', {path: '/:client_id'});
or
this.route('client', {path: '/client/:client_id'});
If your id happens to be part of your model you can retrieve from the model itself.
For example, if you have a route with an object Bill as a model, and the path bills/:billId, on your controller you can retrieve it this way:
this.get('model').id
I just came across this question since I too was wondering what was the best way to do this. I chose to go via the route of returning a hash from the model rather than setting parameters in the route.
So in your case I would do the following:
model() {
Ember.RSVP.hash({client: <get client>, id: id});
}
And then in the controller or template I can access the client by calling
model.client
and get the id by calling
model.id
I personally feel this is a cleaner way of accessing the id as compared to setting a param on the route. Of course I am assuming that the id is not already set on the model. Otherwise this entire exercise is pointless.
I would like to create a route for / that loads another route, say 'posts'. It seems that the only two solutions are to configure Ember's IndexRoute:
App.IndexRoute = Ember.Route.extend({
redirect: function() {
return this.transitionTo('posts');
}
});
OR
Map our 'posts' resource to the / path:
App.Router.map(function() {
return this.resource('posts', { path: '/' });
});
The first solution does not seem reasonable because it always sends visitors to /posts instead of having an actual base path of /. The second solution does not seem reasonable because it only allows posts to be viewed from / and not /posts. The second solution inherently creates strange nested URLs like /new for a new post instead of /posts/new.
What is the most idiomatic way to configure / to load another route instead of redirecting, while still making the target resource available from its normal URL? In other words, I would like the / path to access posts, and still have posts available via /posts.
Another way to go is to have your IndexController needs the PostsController, and then you can use render in your index template to render the posts.
App.IndexController = Ember.Controller.extend({
needs : ["posts"]
});
And then your index template might just be
{{render 'posts'}}
I think what you want to do is the following:
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.get('store').findAll('post');
},
setupController: function(controller, model) {
this.controllerFor('posts').set('content', model);
}
});
That way the controller for this route will be an ArrayController filled with all your posts. And you can still use your /posts route whichever way you like. By default this would be App.IndexController (which you can override to implement custom functionality).
Alternatively, if you wanted to use a different controller (say App.PostsController), you could specify that in the routes renderTemplate hook. So if you wanted to use your posts template and your App.PostsController used in your App.IndexRoute, you would include:
renderTemplate: function() {
this.render('posts', { controller: 'posts' });
}
For more details have a look at the routing section of the Ember.js guides.
I have a very basic route setup that allows me to first show "all" records for some object. Then if the user selects a dropdown they can filter this down using a date.
I recently upgraded to RC2 and realized that "needs" has replaced or will soon replace controllerFor.
I'm curious how I can use "needs" in the below situation where I need the nested / inner route for "records.date" to change the content for the parent "records" route when a date is selected.
What is missing from below is that inside the App.RecordsDateRoute I need to change the content of the "records" controller to be a new filter (by date this time) and everything I seem to do just dumps the handlebars template and show nothing -even when I try to use something simple like
this.controllerFor("records").set('content', App.Record.find(new Date(model.loaded)))
from within the setupController method of the RecordsDateRoute
App.Router.map(function(match) {
return this.resource("records", { path: "/" }, function() {
return this.route("date", { path: "/:date_loaded" });
});
});
App.RecordsController = Ember.ArrayController.extend({
selected: 0,
dates: Ember.computed(function() {
return App.Date.find();
}).property()
});
App.RecordsIndexRoute = Ember.Route.extend({
model: function() {
this.controllerFor("records").set("selected", 0);
return App.Record.find();
}
});
App.RecordsDateRoute = Ember.Route.extend({
model: function(params) {
//the controllerFor below seems to be working great ... but what about needs?
this.controllerFor("records").set("selected", params.date_loaded);
return App.Date.create({ loaded: params.date_loaded });
}
});
With rc2, instances of other controllers can be retrieved via "controllers.controllerName", in you case it would be this.get('controllers.records').
The "needs" declaration makes the referencing controller sort of import the reference to the other controller; in your case, the date controller would be:
App.RecordsDateRoute = Ember.Route.extend({
needs: ['records'],
model: function(params) {
this.get("controllers.records").set("selected", params.date_loaded);
return App.Date.create({ loaded: params.date_loaded });
}
});
Regarding App.Record.find(new Date(model.loaded)), find() expects an id or an object whose keys and values will be used to filter the collection of models, but you're giving it a Javascript date.
Did you mean App.Record.find(new App.Date(model.loaded)), or maybe something like App.Record.find({ loaded: model.loaded }) /* assuming it's already a Date */?
There is also an initController(controller, model) method in the route called , maybe you could use that instead of "overloading" the model() method with too many responsibilities. http://emberjs.com/api/classes/Ember.Route.html#method_setupController
I recently upgraded to RC2 and realized that "needs" has replaced or will soon replace controllerFor.
To access another controller from route hooks you should continue to use controllerFor. Controller.needs is for communication between controllers, it replaces the now deprecated use of controllerFor method on controllers. AFAIK there is no plan to deprecate controllerFor on ember Routes.
I'm curious how I can use "needs" in the below situation where I need the nested / inner route for "records.date" to change the content for the parent "records" route when a date is selected.
For this use case it would be best to stick with controllerFor. It is possible to use needs this way, by specifying that App.RecordsDateController needs = ['records'] you could access the records controller via controller.get('controllers.records') from within your route's setupController hook.
What is missing from below is that inside the App.RecordsDateRoute I need to change the content of the "records" controller to be a new filter (by date this time) and everything I seem to do just dumps the handlebars template and show nothing -even when I try to use something simple like this.controllerFor("records").set('content', App.Record.find(new Date(model.loaded))) from within the setupController method of the RecordsDateRoute
App.RecordsDateRoute = Ember.Route.extend({
model: function(params) {
return App.Date.create({ loaded: params.date_loaded });
},
setupController: function(controller, model) {
var recordsController = this.controllerFor("records");
// Moved this from model hook, since here you are 'setting up a controller'
recordsController.set("selected", model.date_loaded);
// Set query based on current route's model
var query = { loaded: model.loaded };
recordsController.set("content", App.Record.find(query));
}
});