Can Ember handle multiple routes to a single resource? - ember.js

I want to show the profile page on my web app either by username or user_id. I've tried the following with no success, any ideas?
MyApplication.Router.map(function () {
this.resource('user', { path: '/user' }, function () {
this.resource('profile', {path: '/profile/id/:user_id'});
this.resource('profile', {path: '/profile/:user_username'});
});
this.resource('notFound', {path: '/notfound'});
});

It seems Ember shouldn't really be used in this way. I've read through issues 551 and 571 on Embers Github. I think it's best to stick with showing a user by id to avoid working against the framework.

You can merge those two resources into one as follows:
MyApplication.Router.map(function () {
this.resource('user', { path: '/user' }, function () {
this.resource('profile', {path: '/profile/id/:value'});
});
});
MyApplication.ProfileRoute = Ember.Route.extend({
model: function(params) {
var value = params.value;
if (isNaN(value)) {
return this.store.find('user', { username: value });
} else {
return this.store.find('user', value);
}
}
});
If the value in the URL is a number it will do a findById; otherwise it will do a findQuery. Obviously this approach will fail if some username is a number.

If the URL is the important part for you, you could change the resource names and keep the url prefix the same, for example:
MyApplication.Router.map(function () {
this.resource('user', { path: '/user' }, function () {
this.resource('profileByUserId', {path: '/profile/id/:user_id'});
this.resource('profileByUsername', {path: '/profile/:user_username'});
});
this.resource('notFound', {path: '/notfound'});
});
Hope it helps.

May be with nested routes for the profile resource
MyApplication.Router.map(function () {
this.resource('user', { path: '/user' }, function () {
this.resource('profile', function(){
this.route('byid',{path: '/id/:user_id'});
this.route('byname',{path: '/name/:user_username'});
});
});
this.resource('notFound', {path: '/notfound'});
});
But remember to implement serialize for the definition of the route with user_name
http://emberjs.com/guides/routing/defining-your-routes/
The previos aproach is also valid IMHO

Related

Ember Routes How To?

My problem is "simple", but I could not resolve it with Ember....
It is a Small Library App, with authors and books with those routes working fine
this.resource('books', function () {
this.route('edit', {path: '/:book_id/edit'});
this.route('show', {path: '/:book_id'});
});
this.resource('authors', function () {
this.route('new');
this.route('edit', {path: '/:author_id/edit'});
this.route('show', {path: '/:author_id'});
});
Now I want to add a route which allows me to register new books, using a link from a current author template /authors/156
The route must open a books/new template, and link the new book object with his author: ie I want to show <h1>New book from {{author.name}}</h1>
What route should I add to the existing ones?
How can I pass the author reference to the new book object?
I see three ways of doing it:
Put it under the books resource and require the author as a route parameter:
this.resource('books', function() {
this.route('new', { path: '/new/:author_id' });
});
Put the route under the books resource, but put the author in a query parameter instead.
this.resource('books', function() {
// Declare required query parameter on controller for `new` route
this.route('new');
});
Put the route under authors and require the author in the URL:
this.resource('authors', function() {
this.route('new_book', { path: '/:author_id/new_book' });
});
I would suggest the third option, as I think it's the cleanest. In your controller, you can create a new book fairly easily:
export default Ember.Controller.extend({
actions: {
createBook: function() {
var author = this.get('model');
var book = this.store.createRecord('book', {
author: author,
...
});
book.save();
}
}
});
I've tried and succeed with the second suggested method, query params.
Router:
this.resource('books', function () {
this.route('new');
this.route('show', {path: '/:book_id'});
};
Route
App.BooksNewRoute = Ember.Route.extend({
queryParams: {
author_id: {
refreshModel: true
}
},
model: function (params) {
var newBook = this.store.createRecord('book');
this.store.find('author', params.author_id).then(function (author) {
newBook.set('author', author);
});
return newBook;
}
});
and Controller
App.BooksNewController = Ember.ObjectController.extend({
queryParams: ['author_id'],
author_id: null,
actions: {
save: function () {
var controller = this;
this.get('model').save().then(function (book) {
controller.transitionToRoute('books.show', book);
}, function (error) {
console.error(error);
});
},
cancel: function () {
this.get('model').rollback();
this.transitionToRoute('index');
}
}
});

Ember: object resolving of nested resources

I've recently started using Ember.js with Ember-CLI and I'm pretty excited.
But there are some things that are not clear for me.
Here is my router:
this.resource("authenticated", { path: '/' }, function() {
this.resource("contacts", function() {
this.resource("contact", { path: ':id' });
});
this.resource("chats", function() {
this.resource("chat", { path: ':id' });
});
this.resource("settings", function() {
this.resource("setting", { path: ':id' });
});
});
The question is - why after 2nd nesting 'resolver' starts finding objects outside of 'authenticated' resource?
For example
my-app/pods/chats/index/view
But expected
my-app/pods/authenticated/chats/index/view
Why is 'authenticated' missed ?
Your authenticated route is not applied in the url because you assigned it's url to the root: { path: '/'}.
You should either change the path to 'authenticated' or remove it all together:
this.resource("authenticated", function() {
...
});
Now, however, authenticated is only rendered when a user navigates to my-app/pods/authenticated. If you still want to render authenticated as index, you should prefix your nested resources:
this.resource("authenticated", { path: '/' }, function() {
this.resource("contacts", { path: '/authenticated/contacts' }, function() {
...
});
this.resource("chats", , { path: '/authenticated/chats' }, function() {
...
});
...
});
I hope this helped you.

Nested routes in Ember

I want my settings area to look like this:
..
/settings/:accountId/users
/settings/:accountId/users/:userId
I have my router defined as follows:
Router.map(function() {
this.route('login');
this.resource('settings', { path: 'settings/:settings_id' }, function() {
this.route('overview');
this.route('users');
});
});
This works for displaying the users listing page. I'm not sure how to take it to the next step though and have both a route and a resource for /users and /users/1.
Thanks.
In the latest versions of Ember, route's can have sub routes (for namespace sake).
Router.map(function() {
this.route('login');
this.resource('settings', { path: 'settings/:settings_id' }, function() {
this.route('overview');
this.route('users', function(){
this.route('user', {path:':user_id'});
});
});
});
http://emberjs.jsbin.com/cutayuniga/1/edit?html,js,output
If you're in an older version, you will have to make users a resource.
Router.map(function() {
this.route('login');
this.resource('settings', { path: 'settings/:settings_id' }, function() {
this.route('overview');
this.resource('users', function(){
this.route('user', {path:':user_id'});
});
});
});

Redirect only when the parent is directly addressed

This is my code:
App.Router.map(function () {
....
this.resource('profile', function () {
this.route('user');
this.route('user.edit', { path: '/:user_id/edit' });
this.route('password');
this.route('company');
this.route('company.edit', { path: '/:company_id/edit' });
this.resource('products', function () {
this.route('index');
this.route('show', { path: '/:product_id/show' });
});
});
....
});
App.ProfileRoute = Ember.Route.extend({
redirect: function () {
this.transitionTo('profile.user');
}
});
And I have a link-to:
{{#link-to "products.index" }}<i class="icon-barcode icon-2x pull-left icon-border"></i>{{/link-to}}
Which is linking to #/profile/products/index. But this triggers the redirect in ProfileRoute, which is not desired: the redirect should only be triggered whenever #/profile or #/profile/index is accessed.
How can I do this?
Change from App.ProfileRoute to App.ProfileIndexRoute. Like the following:
App.ProfileIndexRoute = Ember.Route.extend({
redirect: function () {
this.transitionTo('profile.user');
}
});
App.ProductsRoute have as parent the App.ProfileRoute route, so the redirect (a.k.a beforeModel), is triggered, and you get your undesired behavior. Using App.ProfileIndexRoute fixes it, because the App.ProfileIndexRoute is just triggered when calling /profile
I hope it helps

How to access a parent model within a nested index route using ember.js?

I have the following route structure
App.Router.map(function(match) {
this.route("days", { path: "/" });
this.resource("day", { path: "/:day_id" }, function() {
this.resource("appointment", { path: "/appointment" }, function() {
this.route("edit", { path: "/edit" });
});
});
});
When I'm inside the AppointmentIndexRoute I'm looking for a way to create a new model using some meta day from the day (parent) model but because the day model does not yet know about this appointment I'm unsure how to associate them until the appointment is created / and the commit is fired off.
Any help would be much appreciated
From within the AppointmentIndexRoute's model hook you can use modelFor('day') to access the parent model. For example:
App.AppointmentIndexRoute = Ember.Route.extend({
model: function(params) {
day = this.modelFor("day");
...
}
});
Another example is here: emberjs 1.0.0pre4 how do you pass a context object to a resource "...Index" route?
What if I am not using ember data? How do I get the parent id in a route like
this.resource('workspace',function () {
this.resource('workflow', {path: '/:workspace_id/workflow'}, function () {
this.route('show', {path: '/:workflow_id'});
});
});
This code will not work:
App.WorkflowShowRoute = Em.Route.extend({
model: function(params) {
var ws = this.modelFor('workspace'); //ws is undefined
return this.store.find('workflow', params.id, ws.id);
}
});
EDIT:
I found a workaround, it's not ideal but works exactly the way I want it.
this.resource('workspace',function () {
this.route('new');
this.route('show', {path: '/:workspace_id'});
//workflow routes
this.resource('workflow', {path: '/'}, function () {
this.route('new', {path:'/:workspace_id/workflow/new'});
this.route('show', {path: '/:workspace_id/workflow/:workflow_id'});
});
});
And in my workflow route, I can access the workspace_id jus as I expect from the params property:
App.WorkflowShowRoute = Em.Route.extend({
model: function(params) {
return this.store.find('workflow', params.workflow_id, params.workspace_id);
}
});
Finally, here is my link-to inside the workspace.show route helper:
{{#each workflow in workflows}}
<li>
{{#link-to 'workflow.show' this.id workflow.id}}{{workflow.name}}{{/link-to}}
</li>
{{/each}}