Emberjs: controller and route not getting along - ember.js

The example will represent it best, I suppose. So, I have a defined route with a model property, which displays the appropriate image, based on id in url. This worked:
App.DetailsRoute = Ember.Route.extend({
model: function(params) {
return App.Images.find(params.image_id);
}
});
However, I wanted to add an action and... when I set up the controller, the page did not have access to the model part. Controller:
App.DetailsController = Ember.Controller.extend({
saveToServer: function(){
//alert(JSON.stringify());
alert('hi');
}
});
So at this time it's like this: either the model is set and stuff gets displayed and controller doesn't work OR controller works and model not.
Why is this happening?

Related

Params empty in model hook, but paramsFor is not empty

The example code below is how the model hook is supposed to work by default. Strangely, if I don't include the model hook at all, the model is populated correctly. If I include the model hook as below, it doesn't work because "params" is an empty object. However, this.paramsFor('somemodel') returns {somemodel_id: "1"} So, what am I missing here?
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('somemodel', params.somemodel_id);
}
});
Nested routes inherit the parent route's model if you do not specify a model hook. If all you are doing is looking up the model to edit you don't need a model hook, if you are querying the store for something else and need access to somemodel you can access it via this._super(...arguments).
export default Ember.Route.extend({
model: function(params) {
return this.store.find('somemodel', this._super(...arguments).get('id'));
}
});
It seems that params don't propagate to nested routes. My router looks like this:
this.route('somemodel', { path: '/somemodels/:somemodel_id' }, function() {
this.route('edit');
});
The "index" route is implied and is the route that receives the params. The edit route is nested and does not receive the params.

get data from my model to my controller (Ember.js)

Thank you in advance. I have a model and a controller. What I am trying is to access the model data from my controller and be able to play with from my controller. When init: function is fetch, on my console i get (null).Thank you again
//========model==========\\
App.RequestDashboardRoute = App.AuthRoute.extend({
model: function(){
return this.store.find('request');
}
});
//========controller==========\\
App.RequestDashboardController = Ember.Controller.extend({
init: function(){
console.log("model");
}
});
console.log("model"); is only going to log you a string "model"
Also, the model is not set in the controller until after setupController is called in the route (RequestDashboardRoute in your case)
init happens before setupController, to be sure you controller not only has a model before trying to access it but also to execute your logic again if it changes, you can add an observer, and run your logic there
App.RequestDashboardController = Ember.Controller.extend({
modelChanged: function(){
var model = this.get('model');
// your model is ready
}.observes('model')
});

Nested routes loads the parent model

I have a nested route structure like this:
App.Router.map(function() {
this.resource('user', {path: '/user/:user_id'}, function() {
this.route('followers', {path: '/followers'});
});
});
when I hit the user/123/followers route I would expect that it automatically fetch the model from user/123/followers, but it just fetches the user model from user/123 again. What do I need to add so it fetches the right data for the route?
Each route have your own model, and this isn't propaged, by default.
So App.UserRoute model, returns the current model like expected:
App.User.find(params.user_id)
But because App.UserFollowersRoute have your own model hook, then you have to provided it.
You can do this easily using the modelFor.
App.UserFollowersRoute = Ember.Route.extend({
model: function() {
return this.modelFor('user');
}
});
The modelFor look for a model from a named route. So modelFor('user'), will retrieve the model from App.UserRoute.
And in your user/followers template, you will have the current user, in the current context:
<script type="text/x-handlebars" data-template-name="user/followers">
<h2>{{name}} followers:</h2>
<ul>
{{#each followers}}
<li>{{name}}</li>
{{/each}}
</ul>
</script>
Here a sample with this working
Ember will automatically call User.find(123) when you hit /user/123/... because that is the default model hook for App.UserRoute. If you want to fetch additional data when the followers route is accessed, define a model hook for App.UserFollowersRoute:
App.UserFollowersRoute = Ember.Route.extend({
model: function() {
user = this.controllerFor('user');
// Now find and return the list of followers
}
});

Ember (data) linkTo without passing model, just fetch new model

When using the linkTo helper in a handlebars template, Ember sets up the correct URL for the link with the help of the serializer I have added to the route:
serialize: function(slug, params) {
var name, object;
object = {};
name = params[0];
object[name] = slug;
return object;
}
And when I click the link, Ember transitions to the correct page with the correct slug and everything, but it doesn't have the correct data, and it says that. I believe it's because what I pass to my linkTo statement as second parameter is just the slug and not the whole model.
Is it possible to get Ember to simply fetch the data as it would if I just typed the URL into the address bar instead of relying on the model (that is not) passed to the linkTo statement?
UPDATE
I have tried this inside the activate method on my route, but now it seems the problem is that the rendering has to wait until this is done.
activate: function() {
this.context.isLoaded = false;
this.model(this.context.query.slug);
}
Any ideas? Maybe even with a prettier solution?
The solution I came up with at last, with help from some guys on IRC, was to use the setupController hook, like you mention, Darshan, and the serializer like this:
CustomRoute = Ember.Route.extend({
setupController: function(controller, model) {
var modelName = this.routeName.substr(0, 1).toUpperCase() + this.routeName.substr(1),
slug = model;
if (model.hasOwnProperty('slug'))
slug = model.slug;
controller.set('model', App[modelName].find({'slug': slug}));
},
serialize: function(slug, params) {
var name, object;
object = {};
name = params[0];
object[name] = slug;
return object;
}
});
This way, you can supply just the slug of the route as the second parameter to the linkTo helper instead of a model, and the serializer will set the URL up properly, and then the setupController will check if the model has a property slug, which properly means it's a proper model, and if it does not, it just guesses that the model is simply the slug, and then it will use the DS.Model.find method to return a promise to the controllers model store.
Because setupController is called everytime a route is entered, where as the model hook is only called sometimes, the DS.Model.find method will be used everytime to fetch the data via the promise, and voila - fetch data each time you enter a route.
This assumes that you use Ember.Data and that your model object is called App.*route name* starting with a capital letter, but it can easily be modified to fit whatever need one might have.
For all of the routes in my app I now subclass (extend) from this route thus getting my desired behaviour for all of my routes.
You can try using the slug name in the Route and then loading data for the Route using findQuery instead of find.
App.Router.map(function() {
this.resource('product', { path: '/product/:slug' });
});
App.ProductRoute = Ember.Route.extend({
model: function(params) {
return App.Product.query({name:params.slug});
}
});

Specify controller and model on a view that doesn't have a router

I have a simple app that is using ember-data to load from a RESTful web service and display the data using the route to specify the model.
App.AreasRoute = Ember.Route.extend({
model: function() {
return App.Area.find();
}
});
Then I can render the data in the handlebars template using {{#each content}}
But I want to have a second area of data from a different model displayed on the page as well. I started by creating a View and then rendering the view as part of my application template using {{view App.AnotherView}} which correctly renders the view.
However, this view doesn't have a route and therefore I have nowhere to tell it where to get it's data from. How do I do this?
The best place to load additional content is in the setupController hook of the route.
For example, if you define your route as
App.AreasRoute = Ember.Route.extend({
model: function() {
return App.Area.find();
},
setupController: function(controller) {
controller.set('someArea', App.Area.find('area_id'));
}
});
Then the Area model with id area_id can be accessed by {{someArea}} in your template.