emberjs using multiple paths / urls for one route - javascript

In Ember I can use this:
App.Router.map(function() {
this.route('accomodations');
});
so if one goes to /accomodations it will load that view.
I can also add:
App.Router.map(function() {
this.route('accomodations', { path: '/travel' });
});
so if one goes to /travel, it will go to the same view.
I want to be able to have /accomodations and /travel go to the same view? is this possible?
I know that this:
App.Router.map(function() {
this.route('accomodations');
this.route('accomodations', { path: '/travel' });
});
Will do what I'm asking, but if they go to accommodations, it should show that in the url, it always shows travel. I'm not even sure if the final piece of code is best practice.

You can simply interchange the two route-path definition lines:
App.Router.map(function() {
this.route('accomodations', { path: '/travel' });
this.route('accomodations');
});
The last definition takes the precedence for URL display in {{link-to ...'accomodations'}} and Route#transitionTo('accomodations') in-app transitions, though entering the app by '/travel' will leave the URL as is.
(EmberJS 1.11.3, 2.12.2)

Using redirection
In router.js
App.Router.map(function() {
this.route('accomodations');
this.route('travel');
});
In routes/travel.js
App.TravelRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('accomodations');
},
});
You do not have to put these in separate files (that's just where I would put them).
What this does is register two routes with the router. Pick one of them to be the "main" route, and the other the "alias" route. In this case, accomodation is the main route, and travel is its alias. When the user visits /travel, they get redirected to /accomodation.
This would be the default/ standard Ember way of accomplishing this, and if this sounds good to you, go for this.
Another possible solution
If you do not wish to have redirection happen, for some reason, and want the URL seen by the user to stay the same, but still display the same things, and behave in the same way, this is also possible.
In this case, you would create two of every single Ember unit (route, controller, view, template). The smart way would be to create a base class route, and have both App.TravelRoute and App.AccomodationRoute trivially extend it; create a base class controller, and have both App.TravelController and App.AccomodationController trivially extend it; same for views, if you have them.
Templates, OTOH, are a little trickier, because there is not way to extend them (that I know of). SO what you would need to do, is create either a partial or a component (decided which works better for you), and then reuse that partial/ component in both templates/accomodation.hbs and templates/travel.hbs

Related

Using the same URL for multiple nested ember routes

I have a case using Ember where I want to make the top level URL available (ie. localhost:4200/demo), and have all the routes underneath also display the same URL (localhost:4200/demo). So the route file, if possible would look something like:
this.route('demo', function() {
this.route('one', { path: '/' });
this.route('submit', { path: '/' });
});
I understand that ENV.locationtype can be set for the whole app, but is there a way to conditionally set this for specific URLs underneath a parent URL?
Generally when you end up hitting major snags like this it is because Ember is implicitly trying to tell you that what you are doing isn't a good idea.
Is there a particular reason that you don't want your sub-routes to affect the URL in any way? Could you get by with random values in the URL if your prime purpose is to obfuscate things?
Ember uses the URL to work out what state things should be in in your app. If you don't want to use the routes at all you wouldn't have to, but then at that point you are dealing with a nested hierarchy of components that you have to switch between yourself. Which would in essence be akin to using React without a router ...
By default, Ember can manage URLs, or it can be set to not manage them, but it seems like the desired intent is to have it do both in a single environment, which is not logically allowed.
If none is declared for ENV.locationtype, then Ember's default URL management is turned off. This is an "environment-wide" configuration.
If the Ember Router is being used to map nested routes, and default URL management is in play, then observe that you cannot have the same URL path defined for multiple, sibling, child routes.
A further observation, is that your attempt above is tapping into functionality governed by the single index route that is available at every nesting level within the Router map. However, a route cannot have multiple index routes. Only the last one defined will be recognized.
Router.map(function() {
this.route('demo', function() {
this.route('one', { path: '/' }) // <-- this is over-ridden by "submit"
this.route('submit', { path: '/' }) // <-- this defines an "index" route for demo
})
})

insert component without calling handlebars helper or a controller with outlet

I want to insert a component into controller template without using the handlebars helper (component "component-name"... or component-name). Or through a controller in an outlet (or as long as the solution works for a component that wants to insert another component, then it's fine, I don't think outlets work in components).
In other words:
App.IndexController = Ember.Controller.extend({
actions: {
insertComponent: function() {
var component = this.container.lookup("component:my-inserted", { singleton: false });
component.set("layoutName", "components/my-inserted");
// to be like handlebars-inserted component, what do i do here?
}
}
});
You can use test with this: http://emberjs.jsbin.com/popozanare/4/edit?html,js,output
Why?
Thinking of a way of to have clean modal syntax, such as the "openModal" syntax described in the Ember Cookbook: http://guides.emberjs.com/v1.10.0/cookbook/user_interface_and_interaction/using_modal_dialogs/.
The problem is that the source context is lost, as the modal is within the ApplicationRoute. I want the same syntax when calling a modal, but keeping the hierarchy. You can keep the hierarchy using https://github.com/yapplabs/ember-modal-dialog, which requires a mapping of variables... which i don't like either (but will likely implement if I have no other choice).
TD;LR: Want to open modal within the controller/component (context) that called it without scaffolding in the controller/component that called it (mapping variables, etc).
Edit:
On second thought, using a container view might be cleaner than mapping variables, found in this solution: http://jsbin.com/hahohi/1/edit?html,js,output. Still needs scaffolding though. Thanks #user3568719.
That cookbook is a bit outdated, but if you are looking for a "clean" way to handling modals in your app I would suggest named outlets.
Add it to your application or auth template {{outlet "modal"}} and when you want to bring up the modal you can catch the action on the corresponding route and then render into that named outlet like so:
this.render('your-desired-modal-template', {
into: 'auth',
outlet: 'modal'
});
And when you want to dismiss it simply disconnectOutlet like so:
this.disconnectOutlet({
outlet: 'modal',
parentView: 'auth'
});
This is the way we've been going about it, I m open to suggestions/better methods.

How to reference ember.js controllers that are in nested folders?

I'm building an EventController that has little modules of logic within sections or div's of the event screen.
Say for instance, event details may be in the main Event template but a small section might be the user's status with the event such as whether they RSVP'd etc. but since it's controlled by a different model than the event I'd think it should have it's own controller.
Would I put this in the EventController like such:
Controller = BaseController.extend
needs: ['event/user-status-area']
userStatusArea: Ember.computed.alias("controllers.event.user-status-area")
This obviously isn't working otherwise I wouldn't be here... but I'm looking for suggestions.
I'm very new to ember / ember-cli concepts so I'm sorry if I'm just blatantly way off base here.
In my brain, I would imagine keeping everything about an event centralized under the one EventController...
Am I missing something big? Is this possibly where the "Router" comes in?
UPDATE:
If so, I'd imagine it might look something like this in Router:
Route = BaseRoute.extend
model: (params) ->
#store.find('event',params.id)
renderTemplate: (controller,model) ->
userStatusController = controller.get('userStatusArea')
#render 'event'
#render 'event/user-status-area',
into: 'event',
outlet: 'user-status-area',
controller:userStatusController
model: model.event_user.find(#get('session.current_user.userId'))
No idea if this would even be considered a best practice for ember?
I guess this would be the question... what is the best way to create this type of structure?
One way is to create a nested route:
router.js
this.resource('event',{path:'event/:id'}, function(){
this.route('userStatus');
})
in the event template, you would add an {{outlet}}
When you transition to event/{id}/userStatus, the outlet would be automatically rendered with the templates/event/user-status.hbs template.
When you reference controllers/views etc. in ember-cli with a filename e.g. user-status, you need to reference it in camelCase:
needs: ['event/userStatus'],
not user-status.
Hope this helps.

Using template and controller multiple times on different routes in Ember

In my Ember application I have a categories controller and corresponding template.
I want to use this on various routes: When browsing, when advanced searching and when adding a product.
I tried to put it together as this:
#router
this.resource("categories", { path: "/*scope/select-category" }, function() {
} );
Scope could be 'search', 'products' or 'products/new'. It would make URLs very pretty!
But I'm having difficulties finding back the *scope value from my controller, I found it somewhere nested deeply, but with 'products/new' as the scope the value is 'products'.
Also I already experienced some strange behavior, for example, on a fresh page load for 'products/select-category' it wants to go to 'products.product', trying to find the product with ID='select-category'. Which is of course not what I want.
The categories route is the first route in the list so I assumed it would always pick that first..?
I'm doubting if this is the right way to do this.
You probably should do it this way, by handling the scope on a separate route:
#router
this.resource("scope", { path: "/scope/:scope" }, function() {
this.route("categories", { path: "/select-category" }
} );
This way you can handle scope nicely in the ScopeRoute, with a proper scope parameter.

EmberJS: How to transition to a router from a controller's action

I have an action:
{{action create target="controller"}}
which I have targeted to the bound controller (rather than the router) like this:
App.AddBoardController = Ember.Controller.extend
create: ->
App.store.createRecord App.Board, {title: #get "boardName"}
App.store.commit()
//TODO: Redirect to route
How do I redirect back to a route from the controller action?
Use transitionToRoute('route') to redirect inside an Ember controller action:
App.AddBoardController = Ember.Controller.extend({
create: function(){
...
//TODO: Redirect to route
this.transitionToRoute('route_name');
}
...
In fact, this is not Ember idiomatic. From what I know, and what I have learnt from Tom Dale himself, here are some remarks about that code:
First, you should not transitionTo from elsewhere than inside the router: by doing so, you are exposing yourself to serious issues as you don't know in which state is the router, so to keep stuff running, you will quickly have to degrade your design, and by the way the overall quality of you code, and finally the stability of your app,
Second, the action content you are showing should be located inside the router to avoid undesired context execution. The router is indeed a way to enforce a coherent behavior for the whole app, with actions being processed only in certain states. While you are putting the actions implementation into Controllers, those actions can be called at anytime, any including wrong...
Finally, Ember's controllers are not aimed to contain behavior as they rather are value-added wrappers, holding mainly computed properties. If you nevertheless want to factorize primitives, maybe the model can be a good place, or a third party context, but certainly not the Controller.
You should definitely put the action inside the router, and transitionTo accordingly.
Hope this will help.
UPDATE
First example (close to your sample)
In the appropriated route:
saveAndReturnSomewhere: function (router, event) {
var store = router.get('store'),
boardName = event.context; // you pass the (data|data container) here. In the view: {{action saveAndReturnSomewhere context="..."}}
store.createRecord(App.Board, {
title: boardName
});
store.commit();
router.transitionTo('somewhere');
}
Refactored example
I would recommend having the following routes:
show: displays an existing item,
edit: proposes to input item's fields
Into the enclosing route, following event handlers:
createItem: create a new record and transitionTo edit route, e.g
editItem: transitionTo edit route
Into the edit route, following event handlers:
saveItem: which will commit store and transitionTo show route, e.g
EDIT: Keep reading, Mike's answer discusses some of the problems with this approach.
You can just call transitionTo directly on the router. If you are using defaults this looks like App.router.transitionTo('route', context).

Categories

Resources