How to communicate data between controllers in Ember.js? - ember.js

I am in the painfully slow process of learning Ember and find the guides and documentation severely limited when it comes to non-trivial examples.
To my question now.
Given the following router definition:
App.Router.map(function () {
this.resource('home', function() {
this.resource('weather', function() {
this.route('site', {path: '/:weather_site'});
});
});
When the user enters the home.weather.index route the model hook executes and fetches all weather information from the server. When the user then enters home.weather.some_site the model hook of the new route would bring weather data for that particular site from the server. How can this redundancy be prevented? In other words, how can controllers communicate data to each other? Should I use the setupController hook in each Route to achieve this or are there better ways?
Are there any good resources to help me understand the data flow in and out of Ember? Are there any good resources to help me learn Ember faster than digging into the source?

How can this redundancy be prevented?
It's not clear if/how/why the model hook for home/weather/index would fetch all weather information from the server. If that's desired behavior, then totally agreed there is no reason to fetch the same data when user enters home/weather/site.
If you are using ember-data there should be no redundancy since:
when user visits home/weather/index App.Site.find() fetches all weather data
when they visit home/weather/site App.Site.find(weather_site) returns site from cache and does not make a new request to the server
if user visits home/weather/site directly (or refreshes browser) then App.Site.find(weather_site) will call server and fetch just data for that site.
So unless there is something I'm missing there is no redundancy to prevent.
In other words, how can controllers communicate data to each other?
Seems unnecessary, but since you ask: Controllers communicate with one another via bindings. You declare a dependency from one controller to another via the controller's needs property, then Ember inject's a that dependency automatically. See the ember guide dependencies-between-controllers for more on how this works.
Should I use the setupController hook in each Route to achieve this or are there better ways?
That shouldn't be necessary in this case.
Are there any good resources to help me understand the data flow in and out of Ember?
Not clear what you mean by data flow. Best guess is that you'd learn a lot from Luke Melia's gothamjs presentation
Are there any good resources to help me learn Ember faster than digging into the source?
Reading the source is always a good option, but there are many other resources. I recommend checking out embercasts and ember weekly

Related

EmberJS "detail" page fetches the model automatically - is this normal?

Long time reader - first time questioner here.
I am developing a medium sized application in EmberJS which is a framework that I have been using for a while.
Today I have realised that it fetches model data from the server without me writing any code.
I have a main route called "students". Then there is a "list" sub route where the model() function of this route calls the store to fetch all the students and lists them on a table.
On each row of this table I link to another sub route called "detail" where it accepts the ID of each student as an argument. However inside the route.js file for this route there is no model() function querying any information about the specific student from the server.
Ember does this automatically somehow as I can see the appropriate network request being made using chrome dev tools.
How is this happening and is it normal?
Thank you in advance.
The Ember router will automatically load a model if it detects a dynamic segment that ends in _id.
Ember follows the convention of :model-name_id for two reasons. The first reason is that Routes know how to fetch the right model by default, if you follow the convention
You mentioned that your api route is /api/student/details/:student_id and I would expect that your ember route is fairly similar.
It detected _id, and called store.find('student', params.student_id) automatically for you when you navigated to that route.
This is completely normal, and is one of the ways Ember encourages you to follow convention - If you do, you don't have to create as much boilerplate.
If you want to avoid the second request, possibly because the list route pulls all relevant data, you can pass the student model instead of the student id.

How should I handle page refreshes in EmberJS?

As I understand from the EmberJS Guide to Routing, you should specify the model you want a route to load in the Route's model hook. The model hook may return a promise, and if it does, the route will pause until the promise resolves.
Therein lies my problem: this approach works fantastically under normal use cases (user triggers a transition from any other route into the route in question.) The problem arises if the user is currently at the route in question.
If the user triggers a page refresh (using the browser's refresh button, or ctrl+r or whatever other trigger there might be, the promise in the model hook causes the user to sit at a blank white page until that promise returns. In large dataset cases, this can be a handful of seconds, which does not make for a great user experience.
So, how do I resolve this issue?
The only solution I have developed is to trigger the data load in the route's activate hook, and manually set the controller's model when that promise returns. I don't like doing this, because I'm circumventing the entirety of Ember's model framework.
I would like the application template to render before the model hook hangs the page, at a bare minimum. Any guidance on how to resolve this would be greatly appreciated.
In case the context is necessary: as the tags imply, I am using Ember-Data. I'm utilizing the RESTAdapter almost entirely out-of-the-box, unmodified.
Routes have sub-states that can be used to render a temporary template while the model is loading. See: http://guides.emberjs.com/v1.10.0/routing/loading-and-error-substates/
The first load/initial blank page is a UX problem that will be solved by Fast Boot, see: http://emberjs.com/blog/2014/12/22/inside-fastboot-the-road-to-server-side-rendering.html
Fast boot is already available through one of Ember's branches, I don't know the name.

Ember.js change route without page reload

I am planning an Ember web app which I want to operate on one page without page reloads.
However, I also want to be able to share the state of the app at any time, and therefore make use of Ember's URL-centric design.
As a total Ember noob, I am wondering if and how Ember accomplishes this (relying on routes, but without page reloads).
Any info is greatly appreciated!
I would recommend reading up on "Query Parameters" (see here) as that is the feature it sounds like you are looking for.

Django Rest/Ember How to connect to models

I am getting started with Ember, and Django Rest Framework and I can't seem to peice together how to connect a model so that Ember can use the data in that model and create a simple drop down box. I have one model that I am starting with that is as such:
id
name
security
status
All I want to achieve is allowing Ember to use the data in this model and create a dropdown like so.
<select id="model">
<option value="model.ID">model.Name</option>
</select>
Can anyone help me with this? I am complete new to Ember and Django Rest.
Without going into a ton of detail, I've created a mini example of what you're looking for
http://emberjs.jsbin.com/Ozimatuj/2/edit
You'll note that I'm using mockjax, so instead of hitting any real endpoint, it's all mocked. Additionally I'd recommend using a client side record management solution (such as ember-data or ember-model). That's another discussion though.
In the application route (which correlates with the root of your app) it hits the model hook (which should return the model associated with that route. I'm returning a POJO of the users. That model is being assigned as the content of the application controller (automatically generated). The the application template is being built, and it's being backed by the application controller. Inside the application template we create an instance of ember select, and we tell it that the content backing it is model (which is the model/content in the application controller). We also say, use bind the user model (you could do id) and the name to the value and the label respectively.
I then bound the value of the select to selectedPerson, so anytime the value changes, the selectedPerson updates, the template which talks about that person will update. Magic. Ember does the rest.
This is a really broad question, so if you have any other questions, please ask a specific question, and I'd really recommend going through the getting started guide, it's really short, but will give you a decent foundation of terminology and methodology of Ember. http://emberjs.com/guides/getting-started/
For Ember Data I'd do a quick read the of the transition document for ED 1.0 beta.
https://github.com/emberjs/data/blob/master/TRANSITION.md
DS.DjangoRESTSerializer = DS.RESTSerializer.extend();
DS.DjangoRESTAdapter = DS.RESTAdapter.extend({
defaultSerializer: "DS/djangoREST"
});

Why does ember use the same controller instance on separate visits to a route?

Problem:
I have a conceptual problem with re-using an old controller instance when the user re-enters the route. In many examples, the controller stores the state of user interaction in instance variables. When the user re-enters the controller those should be reset, but there is no clear mechanism for doing so.
So, there must be a good reason to use a single controller instance. What is it?
How I arrived at this issue:
I ran into a bug in out Ember app, where the controller keeps local state that got out of sync based on the user actions elsewhere. The controller maintains a state whether the user is editing the "name" of a "case". When the controller is instantiated, that is set to "true", but when the user cancels, it's set to "false". Then the user goes away to a different route and comes back to the same route. I get the same controller instance that already has "false" for editing the name. I would expect to have "true" instead.
Ember v.s. Rails:
I'm coming from Rails perspective where controller is instantiated for every request. There is no shared controller state between requests. All instance variables are local to the request, so they can be used safely.
Back to the question:
Why does ember use the same controller instance on separate visits to a route?
The role of a controller in ember and in rails are very different. In rails, as you know, the controller is used as a conduit for the request to prepare the data for presentation. If you consider the use case in ember, this is a role that is primarily played by the router.
In your example you mention that the edit state has gotten out of sync. You can solve this problem in a variety of ways, for example you could move the edit state to the model, so instead of isEditing, you'd call model.isEditing (or just isEditing if you are using an ObjectController). Another option would be to reset the state of the controller when entering the route.
Another example which should illustrate this difference is a save button on a form. Initially you might think "Oh, I'm going to put a save action on my controller". This is logical, when you're thinking like a rails developer, but saving a model is the responsibility of the router (especially if it results in changing the current route as this is something that's intentionally hard to do from a controller).
In ember the role of a controller is as a conduit between the model and the view. The fact that controller instances are re-used is a little confusing, but really isn't that important. When you change or return to a route the model/context of the controller is different, and that is where the state of the view should live... in the model.
Although controllers are usually singleton, when you use {{render}} with a specified model you will get a newly instantiated controller. See rc2 release notes under "Using Render with Multiple Models". I'm new to Ember and this difference confused the heck out of me.
Using a singleton controller when trying to keep per-model-instance user interaction state seems tricky. As jonnii said, you can put the state on the model, and that works but it cruds up the data model. The other thing I have tried is to put a map in the controller (keyed by model, value is an object of user interaction state) but this seems like a clumsy reimplementation of something I'd expect the framework to provide. Still working on this...