Ember: how do you access the model from the router? - ember.js

Based on what I've read (please correct me if I'm mistaken), the logic that handles when a model should be saved and where to transition next should be in the router.
If that is the case, I'm running into a bit of a problem: I don't know how to access the model from the route.
This is my controller (and the console logs "CREATED" after I press submit):
App.ScoutsNewController = Ember.ObjectController.extend
submit: ->
model = #get('model')
model.on 'didCreate', ->
console.log 'CREATED' # I want to redirect to the index after creation
model.save()
I should move that logic into the route, right? Let's try that:
App.ScoutsNewRoute = Ember.Route.extend
model: ->
App.Scout.createRecord()
events:
submit: ->
# Based on what I've read, the right place to put the code you see in the controller is here. How do I get access to the model?
# I have tried #get('model'), #get('content')
Note: I understand that the submit event bubbles up from the view, to the controller, then finally the route, stopping at any one of them that has "submit" defined. So since I want the route to handle it, I removed the controller. I'm able to see any console.log done in the route, I just need to be able to get to the model instance.
I'm using Ember v1.0.0-rc.5-7-g610589a
Thanks!

Two options: this.currentModel or this.modelFor(routeName)
Update
I spoke to Señor Alex Matchneer about this. There are no plans for this.currentModel to go away anytime soon, but he considers this.modelFor(this.routeName) the public API.

what should work is
this.controllerFor('ScoutsNew').get('content')

this.currentModel isn't really the approved way as described here
but in my version of Ember (1.11) this.modelFor(this.routeName) returns null, so this is what worked for me
this.controllerFor(this.routeName).get('model')

You could also use this.controller.get('model'); but there are plans to remove the controller.
Till that we can use the above code to retrieve the routes current model

With Ember 3.0.0 this is a documented way that works for me:
const model = this.controller.model;

Related

How to add properties to Ember model that you don't want to persist into database?

I have a model, which has some properties that I obviously want to fetch from database. In addition to this I want to add a "checked" property to that model, which determines, if the actual model element is checked on the user interface. (for example a model record represents an email, and the checked property determines if it is selected for deletion) And obviously I don't want to persist it to the database, I would like to set a default value to this, and than change it via ui actions).
My guess is that these kind of information should be stored at the controller level, but it is an ArrayController, so a single property in the controller won't do.
I'm sure it's not too difficult to solve, but I'm a newbie, and I could not find the answer in the ember guide.
Thanks!
You are right about using a controller. ArrayControllers have itemControllers. You want to specify an item controller and then put the checked attribute there. For example:
App.MailController = Ember.ArrayController.extend({
itemController: 'email'
});
App.EmailController = Ember.ObjectController.extend({
checked: false
});

Ember hasMany property is empty after save

I am having a problem with a hasMany property, but only under certain circumstances. I have a User model and a Group model. The user has a property:
groups: hasMany('group', { async: true })
In my template, I show the groups:
{{#each groups}}<span class="label">{{this.name}}</span>{{/each}}
When I go to /users/1, I see the groups. Then I can go to /users/1/edit. There, I show a Ember.Select view with multiple=true. The select view shows 'groups' as the selection and 'allGroups' as the full list. This works as expected. 'allGroups' is a computed property on UserEditController:
allGroups: function() {
return this.store.find('group');
}.property()
So far, so good. I can update the selected groups if I want, then save. After the save, I transition back to the /users/1 route. When the user is displayed there (after updating), the selected groups show nothing. No error in the console.
I can refresh the page and the selected groups are shown, showing the new choices I made when updating the user.
This one has me baffled, but I suspect it has something to do with the 'allGroups' function.
What version of Ember-Data are you using? This sounds like known bug that should be fixed in 1.0.0-beta-3:
https://github.com/emberjs/data/commit/4d717bff53f8c93bedbe74e7965a4f439882e259
https://github.com/emberjs/data/issues/1228
http://discuss.emberjs.com/t/hasmany-relationships-and-waiting-for-all-child-models-to-be-loaded/2461/3
The second link contains a workaround that should work if you have to use an earlier version of ember-data.
I ran into this issue before, but in this case you don't need to manually handle the synchronicity. Ember will render the data when it receives it...
Please provide more code and I will take a look, I think this could be related to the way you proceed for saving.
Also, although I am note sure about that, when you proceed to an update your backend, I think, should return the "inserted" or "updated" data. This would help to ensure synchronization with the backend.

Reloading a route's model with server json data and need ember-related opinion

I’m building a map with a search function. Basically, I’d like to store objects from the server within my ember app so that whenever I search for something that collection updates itself with the results from the server so the related view updates itself. It’s all on one page.
So far I have an Application Controller, and a Results ArrayController. Data is shown from the Results Controller. Now I’d need that when a search is requested, it gets JSON from the server and updates the results collection.
First question would be:
How would you build that?
I did a v1 with jQuery only and started a new one with Ember but I’m lost as of how structure-wise should I build it.
I built a small jsbin based on what I have here: http://emberjs.jsbin.com/IYuSIXE/1/
Second question:
How would I change a route's model content? Am I going in the wrong direction?
Thanks a lot
You can do both 1 and 2 with query params, check the documentation here https://github.com/alexspeller/website/blob/a96d9afe4506454b155cc64299e86e558ce3c9f1/source/guides/routing/query-params.md
When your route calls the model it will pass the query params, you can do your search against them
model:function( params, queryParams, transition ) { callToYourBackedEndWithQueryParams}
Second question: How would I change a route's model content? Am I
going in the wrong direction?
When the search is requested, in an action you can call this.transitionTo({queryParams: {sort: 'asc'}});, that will fire up again the model hook and you can do the query against your server again.
What I was looking for is a way to change the model on-the-fly.
So basically if I have this:
App.ResultsRoute = Ember.Route.extend({
model: function() {
// empty array that will contain results
return [];
}
});
I can do this to set the content of the model:
this.get('model').setObjects([{}, {}, {}]);
That way I can dynamically play with the models, load them with objects coming from almost anywhere.

ember nested route doesnt resolve with direct entry

Edit(current jsbin http://jsbin.com/univer/17/edit ) see comments
Output:: http://jsbin.com/univer/3/
Code:: http://jsbin.com/univer/3/edit
I'm not using the ID for the url, I'm using a slug I pass in. I don't know if that has anything to do with the issue but I can navigate directly to the nested route.
If you go here jsbin.com/univer/3#/projects/ , everything works as intended. However, if you try to go here jsbin.com/univer/3#/projects/project-1, the page is blank.
Using the rest adapter, I have the projects view rendering with the same code but the model never get's set on the project view. When you navigate directly to the page, the view renders but all you see is "This is the model:" without the name.
Any help is greatly appreciated. If needed, I can make my API public to test on the REST adapter itself but thought the fixture adapter should work the same.
Brett
First issue is with the setupController method for App.ProjectRoute. It is missing the controller, model arguments.
App.ProjectRoute = Ember.Route.extend({
setupConroller:function(controller, model){
controller.set('model',model);
},
Next issue is that the FixtureAdapter does not support findQuery out-of-box. If you're planning to use RestAdapter instead this might not be important, but if you want to make things work in jsBin using FixtureAdapter will need to reopen DS.FixtureAdapter and add a custom queryFixtures method. Advice on how to do that can be found here: https://stackoverflow.com/a/18165887/983357

ember (+ ember-auth) linkTo loggedIn user profile

To get straight to the point, I have an app with a profile accessible like that:
this.resource('user', {path: '/user/:user_id'});
This can accessed from visitors and (logged in users). Now I also have a menu-bar which has, only for logged in users, a link to the user-profile (so that would be /user/:loggedin-user_id). I am using ember-auth to authenticate the user and ember data for my models.
The problem here seems to be {{linkTo 'user'}} doesn't work, because for one user that should link to /user/28, for the next one to /user/15. Simply to his/her own profile. I kinda get that it doesn't work, because how should ember know what ID to display (though yes, I don't understand the underlying reasons fully).
Ember-Auth does provide App.Auth.get('userId') to get the Id of the currently logged in user, but I don't really know how I can tell ember to know that as well.
So what I had to do know is setting the link manually via
<a {{bindAttr href="App.loggedInUser"}}>
where-as this variable gets set to the right url in the Application controller with App.Auth.get('userId'). This works, but is obviously quite a hack.
Is there any 'ember' way of solving that?
ember-auth dev here.
Straight to solution:
First, ask ember-auth to load the user current user model. Assuming that your user model is called App.User, and it implements App.User.find(id).
App.Auth = Ember.Auth.create
# ...
userModel: 'App.User' # default null
# pass the string, not a class App.User
# access the current user model
# as with all things ember, this is loaded asynchronously
App.Auth.get('user')
(copied from the docs.)
Next, pass this dynamic model to your handlebars links:
{{#linkTo 'user' App.Auth.user}}Link To Current User{{/link}}
Or otherwise - e.g. make it a binding to App.Auth.get('user'), etc.
Just in case, (js) App.get('foo') is equivalent to ember-handlebars App.foo.
Your user route has a dynamic segment. You can pass the user model to the linkTo and the anchor will point to that route for different users depending on the id of user model passed.
{{linkTo 'user' userObj}}Profile{{/linkTo}}
The model passed can be plain object with an id and the default serialization would still work. So if you wrap App.Auth.get('userId') into a object with an id you won't need a full model object.
Here's an example jsbin.