How to Transition to (the current) route - ember.js

In my app I'm able to select a " group" model from anywhere in the app. All groups are loaded into the application's model hook, and then the selectedGroup is saved as a property in the application controller.
A lot of the routes have models that are dependent on the selectedGroup, so when a new group is chosen, I need to reload the current route. From what I've been able to read, the best way to achieve this is to just to transitionToRoute.
Is this the best way to do things? And how do I get the current route, in order to then re - transition to it.
Please comment if further explanation needed! Thanks!
Edit
A possible route's code:
needs: ['application'],
model: function() {
var groupID = this.controllerFor('application').get('activeClass.id');
return this.store.find('student', { group: groupID });
}

Well you can get the currentRoute from the application controller. Since selectedGroup is also saved on the application controller, you can add an observer to it and inside that do your transition. The code will look something like.
App.ApplicationController = Em.Controller.extend({
selectedGroup: '',
onSelectionChange: function() {
var currentRoute = this.get('currentRouteName');
this.transitionToRoute(currentRoute);
}.observes('selectedGroup')
});

Related

Loading/reloading data from an action function without changing the route

I am just starting with ember and trying to do a simple test.
Which, also very simple, got me stuck for some reason and I cant find the answer anywhere.
So I need load data from the server without transition to another route and do it from within a submit action (or any other action for that matter).
I have a simple input form where I type in manually an object ID and
I want it to be loaded say right underneath. Simple enough. Seams to be a three minutes job in angular. Here, I just cant get the hang of communication between route and controller.
So given this little emblem
form submit="submit"
= input type="text" value=oid
button type="submit" Submit
#display
= person
And this route
import Ember from 'ember';
export default Ember.Route.extend({
model: {
person: null
},
actions: {
submit: function() {
var oid = this.controllerFor('application').get('oid');
var person = this.store.find('person', oid);
this.modelFor('application').set('person', person);
}
}
});
This is as far as I could think. I want to click submit with ID of an object and I want that object loaded and displayed in the div#display.
So what am I doing wrong? What is the right way to do it?
First, I don't even know where to put such an action? Controller or route?
If I put it in controller, I don't know how to refresh the model. If I put it in route, I am stuck with the above. Would be also nice to see how to do it if action was placed in the controller.
For simplicity I just do it all in application route, template, controller ...
Thank you
The best place to put your code is on Controller given it responds to UI, so doing that on your controller the code is much more simple.
On this jsfiddle I have put some dummy code which tries to do something what you want to achieve.
//Index Route
App.IndexRoute = Ember.Route.extend({
model: function () {
return ['red', 'yellow', 'blue'];
}
});
//Here my dummy controller.
App.IndexController = Ember.Controller.extend({
oid: 1,
actions: {
submitAction() {
//Here your logic to find record given the input and attach
//the response to the model object as UI is binding to model
//if you add/remove new records they will show up.
//On this example I have added a new object.
this.get('model').addObject('green');
}
}
})
Enjoy!

Emberjs - need to refresh model on transtionTo

I have an Emberjs app that has a search action that needs to be available from all routes. To accomplish this, I've defined the 'search' action in the application route like this:
App.ApplicationRoute = Ember.Route.extend({
actions: {
search: function (query) {
this.transitionTo('search', { queryParams: { q: query } });
}
}
});
The 'q' querystring parameter is defined in the SearchController:
App.SearchController = Ember.ArrayController.extend({
queryParams: ['q'],
q: ''
});
The search route calls a service that queries my database with the query parameter like this:
App.SearchRoute = Ember.Route.extend({
model: function (params) {
return this.store.find('activity', { query: params.q }),
}
});
I know that the model hook is not called on transtionTo, but when the user is already on the search page and wants to search again with a different query, I need to reload the search route with a new model.
Is using transitionTo in the application route the wrong approach in this case?
Any ideas are greatly appreciated!
I would add a named {{outlet}} in your Application template, wherever you want the search results to appear. Then, in your Application route, inside the renderTemplate hook, I would render the search results template into the new outlet, also specifying what controller it should use.
On the controller, you can create a computed property, which would detect changes in the query string (or however you want to supply the search results). This property (or properties) would then feed the data in your search results template.
More on rendering a template inside a route:
http://emberjs.com/guides/routing/rendering-a-template/
If you decide to go with putting the renderTemplate hook in Application route, you can set the Search controller's model (or whatever you want to call it) property from any route which needs to update the model on the search controller for it to display proper results:
this.controllerFor('search').set('model', model);
You can also create a Mixin, which would contain the renderTemplate hook, which you can include in any route you want to do your searches from. In the hook, you could send your route's model into the controller:
renderTemplate: function(controller, model) {
this.render('search', {
into: 'search',
outlet: 'application',
controller: 'search',
model: model
});
}
Play around with some of these techniques. I'm sure I'm missing some details, but I think you can get them to work.

Loading Routes in nested route Hierachy

I am working on a mobile application with Ember. I want to make the user experience as good as possible and try to take into account that on mobile the connection is not always as good, that is why I want to utilize the loading routes with a loading spinner. Unfortunately in one case it is not behaving as I would expect:
In my Nested route Setup:
UserRoute:
UserIndexRoute (=Profile)
UserFriendsRoute
On the UserRoute I only load a small version (=different model) of the user. In 95% of the cases this model is already loaded when I want to navigate there. And in the Subroutes (e.g. UserIndexRoute and UserFriendsRoute I only need the full user.
What I want to achieve is that the UserRoute with its template is directly rendered when navigating to e.g. UserIndexRoute and then in the outlet for the Index part I want the UserLoadingView to be rendered. But the rendering always waits for all promises to be resolved and the UserLoadingView is never shown.
How can I force Ember to render the UserRoute and then the UserLoadingView in the outlet until the UserIndexRoute Model is resolved?
How I implemented it:
afterModel: function(model, transition){
var _this = this,
params = Ember.get(transition, 'params.user');
this.get('store').find('user', params.user_id).then(function(user){
_this.transitionTo('user.profile', user);
});
}
Don't use the index route for fetching the full model, just use it as a means for redirection.
Do something like this:
UserRoute:
UserIndexRoute
UserFooIndexRoute (=Profile) (Naming is up to you)
UserFriendsRoute
Then hook up your index route to fetch the full model and transition to FooIndex when it's completed getting the model, this depends on it being a route with a dynamic segment (:id).
App.UserIndexRoute = Em.Route.extend({
redirect: function(){
var self = this;
fetchTheFullModel.then(function(model){
self.transitionTo('user.fooIndex', model);
}
}
});
If it isn't like that you can do just transition to the other route after the transition and page has finished rendering.
App.UserIndexRoute = Em.Route.extend({
redirect: function(model, transition) {
var self = this;
transition.then(function(){
Ember.run.scheduleOnce('afterRender', function(){
self.transitionTo('user.fooIndex');
});
});
}
});
http://emberjs.jsbin.com/zohav/1/edit
You can read more about the transition promise, and afterRender here Ember transition & rendering complete event

Data sharing in ember

I'm trying to understand how to share data between my controllers/routes.
I have an application that's displaying data about companies. Here are the routes I want:
/ summary info
/companies list of all companies with some more detail
/companies/:id details about a single company
Now, the data required for all three routes is contained in a single array of company data. So, I want that data to load when the app starts up, and then be used for each route. There are also additional methods I will need on the controller that should be shared.
It is clear that the second and third routes are nested, so I can share the data from the CompaniesController when I link to a specific company, by passing in that company's data:
{{#linkTo 'company' company}}{{ company.name }}{{/linkTo}}
But the summary route is where I'm getting stuck. The two options I've come up with:
Create the CompaniesController with any additional methods I need, and create the IndexController by extending it
App.IndexController = App.CompaniesController.extend({});
Then, as far as I can tell, both routes will need to find the models:
App.Router.map(function() {
this.resource('companies');
});
App.CompaniesRoute = Ember.Route.extend({
model: function() {
return App.Company.find();
}
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.Company.find();
}
});
Seems like there should be a better way, since I'll have to repeat this for each new route I add (e.g. /revenue).
Nest the summary route within the companies resource, and give it a path of '/'. What I don't like about this is that the 'nesting' of my UI doesn't match the data. It also seems like I'll have to redefine the model property for each route.
Is there another option that's better?
tl;dr: How should I share data across controllers?
To share data beetwen controllers the correct way would be to use the needs API.
Assuming your CompaniesController has all the data that you want to make available to other controllers you should define it via needs, this can be a simple string, or an array of strings if you define more then one.
App.MyController = Ember.ObjectController.extend({
needs: ['companies'],
myFunction: function() {
// now you can access your companies controller like this
this.get('controllers.companies');
}
});
To make things more easy accessible you could additionally define a binding, for example:
App.MyController = Ember.ObjectController.extend({
needs: ['companies'],
companiesBinding: 'controllers.companies',
myFunction: function() {
// now you can access your companies controller like this
this.get('companies');
}
});
Hope it helps.

How to load an object from an id in an Ember View?

I'm trying to build a view to display a user card, from their id. So ideally my calling handlebars would look something like:
<p>{{view App.UserThumb authorId}}
{{comment}}</p>
And then in my UserThumb view, I'd like to be able to load a model, in some sort of setup method or model function, sort of how I'm using controllers:
App.UserThumb = Ember.View.extend({
model: function(view, authorId) {
User.find(authorId, function(user) { view.set('content', user); } );
}
}
Can anyone help me understand the 'right' or at least a workable way to do this? Worst case I can go and create the objects first, but I'd like to just keep the id around for a bit first, unless that is just totally at odds with the philosphy of Ember.
This should do
{{#each id in listOfIds}}
{{view App.UserThumb idBinding="id"}}
{{/each}}
App.UserThumb = Ember.View.extend({
didInsertElement: function() {
var authorId = this.get('id');
User.find(authorId, function(user) { view.set('content', user); } );
}
}
Only after the view is inserted the didInsertElement hook gets executed which gets the required user
The model hook you re using in your View is only available inside a Route. The model hook can be used to setup the model for a controller.
See here the docs for more info on that.
In the spirit of DRY (Dont Repeat Yourself) I'd like to link to this great SO answer that will help setup a functional application, the ember way.
Hope it helps