Ember Routing: Reusing a resource under multiple parent routes - ember.js

I have the following routing setup:
this.resource('blog',function(){
this.resource('selectimage',{path:"selectimage/:returncontext"},function(){});
});
this.resource('post',{path:":post_id"},function(){
this.resource('selectimage',{path:"selectimage/:returncontext"},function(){});
});
What I would have expected is, when navigating to blog.selectimage and post.selectimage, that the same router,controller and view would be used.
Unfortunately it seems that the last entry wins.
Is it possible to achievie this, without leaving the parent context(post/blog), when navigating to selectimage
(Obviously I could inherit from the base-selectimages-classes, but I'm hoping there is some generic ember way of doing this.)

You cannot have same resource name for two different routes as Ember relies more on naming conventions. But Ember provides ways to reuse the same controller and templates
Rename your selectimage under post to something else
this.resource('post',{path:":post_id"},function(){
this.resource('xxx',{path:"xxx/:returncontext"});
});
And in the router, you could specify the templateName and controller that has to be reused. Something like this should make it reusable
App.xxxRoute = Em.Route.extend({
controllerName: 'selectimage',
templateName: 'selectimage'
});
Sample Demo

Related

How to disable the Ember query parameter router?

I am looking to upgrade Ember for a legacy application that I am supporting. The problem is that Ember's query parameter router is causing application conflicts because the legacy application uses an existing custom query string parser that was written before Ember's implementation was added.
Is there a way to completely disable the Ember query string router so that it will ignore ? characters in the URL? In a different situation I would simply switch to Ember's query string router, however that is not possible due to the constraints on this release.
Thanks!
Here is some of the relevant code:
App.Router.map(function() {
this.resource('search', { path: '/search/:query'});
});
App.SearchRoute = Ember.Route.extend({
model: function(urlParams) {
var queryObj = utils.parseQueryString(urlParams.query);
App.mainSearcher.setQuery(queryObj.q);
}
});

subdirectories within ember controller not working

from this post it seems that sub directories within ember controller should work.
https://github.com/ember-cli/ember-cli/issues/1219
however its not working for me .
here is my code branch like (directory cm contains a child directory views):
/controllers/cm/views/item.js
/routes/cm/views/item.js
/templates/cm/views/item.js
when i try to populate the model in route using the code below i see the data but when i put the same code in controller it never gets executed.
model: function(){
return this.store.find('item',{id: "1"});
}
entry in router.js is as follows:
this.resource('cm', {path: '/cm/:id'} , function() {
this.route('views');
this.route('views.items', {path: '/views/items'});
});
Clearly ember is not able to resolve the controller correctly.
Not sure how to fix this ...
That its becuase the model hook in a route works differently than in the controller.
in a route it is a method that can return a promise, the route will wait for the promise to be resolved before setting up the controller.
in the controller, it is just an attribute, which won't get executed until you getit, and even then, all you will get its a promise.
Wat?! Subdirectories work just fine. First, I'm not sure it's the best idea to use views or items as route names, as they're both very generic, and also used in some of the ember internals and can confuse things. Declaring a model called View could very well even break things in your app.
The controller/route/template structures for your router.js will be as follows:
<controllers|routes|templates>/cm.js
<controllers|routes|templates>/cm/index.js
<controllers|routes|templates>/cm/views.js
And I'm not sure what views.items would look like, because this would probably be better suited to making views a resource instead, or using a dash in the name, in which case the route declaration would be this.route('views-items', {path: '/views/items'});
Overall, I think your router definition should look like so:
this.resource('cms', function() {
this.resource('cm', {path: '/:cm_id'}, function() {
this.route('views');
this.route('views-items', { path: '/views/items' });
});
});
This isn't meant to be a quip--I'm here to help--but I think you need to spend a little more time with Ember's routing documentation to understand the conventions that Ember is expecting for certain router definitions. Also, the ember inspector tool is a really great asset when debugging router issues: https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi

LoadingRoute only called once for dynamic segments

How does one get ember to call the LoadingRoute each time one a dynamic route e.g. product/1 and product/2.
I've create a jsbin to illustrate the problem.
If you don't want to eager load all zoobats, the first time you go to any bat resource, you could change your router to
App.Router.map(function() {
this.route('foo');
this.resource('bat', {path: "/zoo/:bat_id"});
});
Now define App.BatRoute and change link-to's route from 'zoo.bar' to 'bar'. You will get loading for each dynamic route, without adding ZooLoadingRoute and you don't have to eager load all zoobats.
Check this jsbin
A work around that sly7-7 posted which works can be found here
Basically define a LoadingRoute at most one level down from the route with the dynamic segment. For
App.Router.map(function() {
this.route('foo');
this.resource('zoo', function(){
this.route('bat', {path: "/:bat_id"});
});
});
this means having a ZooLoadingRoute in your app.

replaceRoute not working as expected?

I recently wanted some routes in my emberjs app not to show up in the browser history and tried to leverage the replaceRoute functionality that was introduced in the RC1. Unfortunately it doesn't make any difference at all if I use transitionToRoute or replaceRoute.
Let's say I have 3 pages and I want page 1 to be skipped when going back in history.
App = Ember.Application.create({});
App.ApplicationRoute = Ember.Route.extend({
events: {goBack:function(){window.history.back();}}
});
App.Page1Controller = Ember.Controller.extend({
goToPage2: function(){
this.replaceRoute("page2")
}
});
App.Router.map(function() {
this.route("page1");
this.route("page2");
this.route("page3");
});
I've made a little JSFiddle example for testing http://jsfiddle.net/ripcurlx/Qmnrj/3/
Am I using the replaceRoute completely wrong, or is there a better solution to prevent certain routes not to be included in the browser history?
Thanks for any hints!
Unfortunately, this only works with location: "history". Browsers have no support for updating the hash without affecting history, whereas when using history states, there is the provided replaceState method which we can utilize.

"Dynamic segment" in Ember.js?

Throughout the Ember.js documentation, one finds the concept of dynamic segment mentioned at several places. What does it mean?
Updating with a proper sample: Demo | Source
Edit due to questions in comments:
In Ember, think of the Router mechanism as a State Machine: Each Route can be seen as a State. Sometimes tho, a state can have it's own little state machine within it. With that said: A resource is a state which you have possible child states. A PersonRoute can be defined as either as a resource our a route in the <Application>.Router.map callback; it really depends on your end goal. For example, if we think of a resource for a list of people based on a person model, we would potentially have a route to list all records.
App.Router.map(function() {
this.resource('people');
});
With this map, I'm telling my app that it needs a people template (and maybe a view), a people controller and a people route. A resource is also assumed to have a index route, which is implied and you don't have to code it, but if you need to, it would be PeopleIndexRoute, after the name of the resource itself, by convention.
Now I can (a) create a person route under people resource to be a single state of a person record; or (b) I can create a person resource under the people resource, so I would have more options under person resource (edit, detail, delete); or (c) I could create a separate resource for person, and use the path to override the url if I want to.
I sometimes go for option c:
App.Router.map(function() {
this.resource('people');
this.resource('person', {path: 'person/:person_id'}, function() {
this.route('edit');
this.route('delete');
});
});
That would make sense that edit is route since it doesn't have child states , only siblings (delete) and a parent (person). The url for a record would be something like this: ~/#/person/3/edit).
The routes, when not defined as a resource, won't have any child route/state, so you don't have person.edit.index like you have person.index, in other words, routes don't have child, only siblings and resources can have both.
Right now, the Routing Guide is the most solid piece of documentation we have about this. I strongly recommend it.
Dynamic Segment is a part of a route URL which changes according to the resource in use. Consider the following:
App.Router.map(function() {
this.resource('products', function() {
this.route('product', { path: ':product_id' })
}
});
In the stub above, the line:
this.resource('products', function() {
will produce the url
~/#/products
and the following line will produce
~/#/products/:product_id
replacing the dynamic part, you could have an url like this
~/#/products/3
the :product_id is what makes this route dynamic. The router will serialize the id of a resource (for example a Product model) to the URL and it also uses that id to find the a model in your DS.Store. You'll often see this in routes like the following:
App.ProductRoute = Em.Route.extend({
model: function(params) {
return App.Product.find(params.product_id);
}
});
So for this example, if you access ~/#/products/3, the app will then try to load an instance of the Product model from your store or try to fetch from your backend API.
You can see a fiddle that illustrates that here | source here
I also recommend this screencast by Tom Dale where he builds a blog reader app with Ember.js using the router and the ember-data API to load blog records based on the dynamic part of the URL.