Ember Route now is singleton ? Needs confirmation - ember.js

I'm using Ember 1.13.3, and somehow I noticed now that Route is also singleton (?), just like controller.
I was checking it because I notice a bug in my app since I upgraded to 1.13.3, and to confirm my suspicion I added console.log in the init method..., and saw that init method is called only once for the route (I switched to another route and wend back).
Is it new (in Ember 1.13, and onward) ?
I need the confirmation if route is really singleton now, in order to rule out the possibility that this behavior I was observing was due to certain (mis)programming (my code).
Thanks,
Raka

Related

Single callback in Router, to access previous/current url + Route information?

I've been looking around on Google and Stack Overflow for an answer to this: with Ember-cli 2.10, how can I set up a single callback in the Router, which gives me information about the previous and current URL, as well as the name of the Route about to be called? I'd like to pass all 3 of those to an analytics platform.
Every example I've found has either depended on deprecated Ember features, or just plain hasn't worked as expected. Love to hear an answer on this. Also happy to hear what a better design might be, given the above analytics requirements.
All your requirements will be covered in Public Router Service pull request. It includes properties currentRouteName, currentURL, location, rootURL and transitionTo method.
It's in canary build, not yet production ready. to play you need to enable this feature config/environment.js
"FEATURES": {
"ember-routing-router-service": true
}
You can just inject router service anywhere and get the properties.
router: Ember.inject.service(),
Twiddle Copied From Miguel Camba

Ember 2.5 Application Controller not present?

This is a very simple and probably easily resolved one.
I have created an emberjs application controller via ember generate controller application from which I want to return some basic computed properties based on the current path to higher level controllers and components. Basically, something like this:
export default Ember.Controller.extend({
entity: Ember.computed('currentPath', () => {
return this.get('currentPath').split('.')[0];
})
});
Oddly enough, I cannot access these computed properties anywhere (they turn out undefined, even if I replace them with a debug string), and in the Ember Inspector's view tree, the application controller is apparently not even present:
I have an older Ember 1.13.0 app, where I'm using the application controller with no difficulty. Have I missed a deprecation here? Or do I need to register the application controller in a specific location?
okay, I solved this differently using injection of the routing service directly into the component (see Component to be notified on route change in EmberJS 2 for details)

Elesticsearch and Emberjs

I'm trying to wire EmberJS with ElasticSearch. So far, I've read most of the Ember documentation, and found out this adapter for ElasticSearch.
The problem is I can't figure out how to use it (i.e. configure it so that when I call store.save(), my model is sent to ES.
What I have ATM is a newly created project with Ember generator (ember new ), and a generated controller, router, model, etc. My problem is that the Ember document explains how to customise adapters, but not how to use them (or I missed that part). The ES adapter's documentation says :
var App = Em.Application.create();
App.store = DS.Store.create({
revision: 4,
adapter: DS.ElasticSearchAdapter.create({url: 'http://localhost:9200'})
});
which implies to create a Store, whereas I can only see ways to extend it in the Ember documentation. Furthermore, I already have a Store in my application.
So the questions are:
do I need to override the store creation to replace it with the ES one (and where to do that) OR
do I need to extend the existing one, and in this case, how should I do that ?
Also, when it says:
First, load the ember-data/lib/adapters/elasticsearch_adapter.js file
in your application.
where and how that should be done ?
On your first questions/s
do I need to override the store creation to replace it with the ES one
(and where to do that) OR do I need to extend the existing one, and in
this case, how should I do that ?
You're onto the right track in the second part, you will need extend the existing one, but not the store, the adapter in this case.
So if you're using ember-cli, which according to this:
What I have ATM is a newly created project with Ember generator (ember
new )
It seems that you are and so you'll application folder structure should be like this:
app ->
adapters(you need to generate/create this)
components
controllers
models
routes
serializers
services
styles
templates
And now we can answer:
how should I do that ?
If you do not have the adapters folder yet, which you probably don't, just run ember generate adapter application or create a folder adapters, and a file application.js for that folder.
And that then finally leads us to a part of your last question.
load the ember-data/lib/adapters/elasticsearch_adapter.js file in your
application. where and how that should be done ?
import ElasticSearchAdapter from 'ember-data/lib/adapters/elasticsearch_adapter'
export default ElasticSearchAdapter.extend({
})
Now the possible bad news, that adapter is likely very outdated, as it the repository's last commit was 27 Dec 2012.

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.

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...