How can I reuse/dry these routes in ember.js - javascript

I have these routes
this.resource('politicians');
this.resource('politician', { path: '/politicians/:politician_id', function () {
// Non nested interface so non nested politician route.
this.resource('questions', function () {
this.resource('question', { path: ':question_id' });
});
});
this.resource('questions', function () {
this.resource('question', { path: ':question_id' });
});
I'd like the question route to be rendered anywhere (using a modal) in the app without losing the current context, but still have a specific/unique url for each question, knowing that the question you got from the nested questions route and the non nested ones are the same.
this.resource('question', { path: ':question_id' });
The thing is that I don't want to make a custom outlet for that because then I won't have a url for each question.

This sort of problem is best solved by using query-params and hooking up the modal based on params. If you don't want to do that you're really stuck with building questions into each route if you want it to be URL based.
Here's an example: http://emberjs.jsbin.com/ucanam/3566/edit

What you're looking for is Ember's {{render}} helper. Simply place a {{render 'question' questionModel}} inside the modal you wish to use.
You can learn about the render helper here
EDIT:
Here is a jsbin to show the basic idea of how to use a render tag in this way. This jsbin renders the same template in 2 different ways; Once tied to a route url and once by using the render helper.
jsbin here

Related

Trouble with nested resources

I'm new to Ember, and I think I bit off more than I can chew with this practice app, but I intend to learn. I might be completely conceptually off, if so, feel free to offer a better structure for my use case.
My (abbreviated) routing looks more or less like this:
Router.map(function() {
this.resource('shops', { path: '/' }, function() {
this.resource('shop', { path: ':shop_id' }, function() {
this.resource('items', { path: 'admin'}, function() {
});
});
});
});
The intention is that the user will select a shop, then get a list of all possible items with checkboxes where he can decide which are available in that shop and which aren't. So far, I'm just trying to display the list of all items, but it's not working. However, the list of shops - no problem whatsoever.
URL: /
Works. model is all shops.
URL: /1
Works. model is the shop with ID 1.
URL: /1/admin
Error while processing route: items.index Assertion Failed: ArrayProxy expects an Array or Ember.ArrayProxy, but you passed object
Both shops and items controllers are identical:
// app/controllers/shops.js
// app/controllers/items.js
export default Ember.ArrayController.extend({});
The routes are nearly identical:
// app/routes/shops/index.js
export default Ember.Route.extend({
model: function() {
return this.store.find('shop');
}
});
// app/routes/items/index.js
export default Ember.Route.extend({
model: function() {
return this.store.find('item');
}
});
The shop controller does not exist, and the shop.index route is trivial:
// app/routes/shop/index.js
export default Ember.Route.extend({});
What gives?
EDIT: JSBin
The problem with your JSBin turns out to be rather simple. In the simplified router in your original post you have this.resource('items', { path: 'admin'}, function() {});.
Since you pass a function to this.resource that means it has an implicit nested this.route('index').
However, in your JSBin, you have this.resource('items, { path: 'admin' });.
Since you are not passing a function in this case, there is no implicit index route.
The solution is either to add the function bit, or rename App.ItemsIndexRoute to App.ItemsRoute and data-template-name="items/index" to data-template-name="items".
JSBin with the latter: http://emberjs.jsbin.com/dahuge/2/edit?html,js
P.S. I've also prepared a JSBin using just this.route which is currently more future-friendly: http://jsbin.com/mifamu/9/edit?html,js,output
Answered on IRC by one very helpful "locks". Some problems remain, but the big question has been answered with this JSBin. My biggest confusion came from misunderstanding how URLs are handled, and what the role of link-to helper was. What I needed most was the change in the ItemsController:
App.ItemsController = Ember.ArrayController.extend({
needs: ['shop'],
shop: Ember.computed.alias('controllers.shop.model')
});
which would make shop accessible, and a mistake in a template saying items instead of model.

Nested multi column navigation

I am trying to get started with ember.js and have gone through the 'todo' tutorial as well as read most of the guide. However, I can't get this multi column navigation right and unfortunately haven't been able to find a similar example.
So, I am having multiple columns, let's call the first one a list of gallerys.
When the user selects the gallery, I would like to display all the images in the column next to the list of galleries. In the end I will be having more than two levels, but two should do for now. I have managed to display the list of galleries, but as soon as I select one, nothing happens. What am I doing wrong? I am also not quite sure how the best way to map the routes would be.
Here is the link to my code: http://emberjs.jsbin.com/gesereyu/1/edit
This is my router config:
App.Router.map(function() {
this.resource('gallerys', { path: '/' }, function() {
this.resource('gallery', { path: '/:gallery_id'});
});
});
I modified your bin a bit. Here is the working demo. Here are the changes I made.
In the link-to helper specify the route in quotes and all the model data that is to be the dynamic segment.
{{#link-to "gallery" this.id}}{{name}}{{/link-to}}
Instead of rendering the gallerys directly into the 'gallerys' route, render them into the gallerys/index route. This way you will not need to use the renderTemplate.
App.GallerysIndexRoute = Ember.Route.extend({
model: function () {
return this.store.find('gallery');
}
});

Ember.js - Setting a model and routing dynamically via API data

So I'm working on building a dynamic model for a project that reacts to data sent from an API. The api will return, among other things, what your location should be and this in turn becomes the url. So, eg:
{
location: 'xyz'
(...)
}
So currently my router will transition to the right route dynamically. But I still have to hardcode each route ( IndexRoute, LocationXYZRoute, LocationABCRoute, etc).
My goal is to create a single route that handles things dynamically. We'll call it App.LocationRoute and my routes would look something like:
App.Router.map(function() {
this.resource(':location', function() {
this.route(':subLocation')
}
}
Now, I have two architectural questions:
1) Whats a good way to handle this sort of dynamic routing? (I've read through the guide about dynamic routing using the ':post_id' type example, but I think I need a more holistic example to really grasp it.
2) The API sends back a whole host of other data as well. I want to add this to the route's model but I also have some other static models. Doing...
this.controllerFor(location).set('content', APIdata);
... works, but it does not set for routes currently using static models. I tried something like:
this.controllerFor(location).set('apiData', APIdata);
and...
this.controllerFor(location).set('model:apiData', APIdata);
... but neither worked.
Any suggestions?
1) Yes, you should use dynamic segment
this.resource('location', { path: '/location/:location_id' }, function() {
this.resource('sublocation', { path: '/sublocation/:location_id' });
});
2) Are you using ember-data? You could check sideloaded data. Anyway, you could read the json and set the payload of each entity for each specific route.
this.controllerFor('location').set('content', APIdata.location);
this.controllerFor('user').set('content', APIdata.user);
People could help you better, if you separate your questions and create a http://emberjs.jsbin.com/ with isolated each specific case?

EmberJS: ArrayController with Dynamic Segments (Router) but not Store

i was wondering how I could build a "simple" app for:
/photos/ (shows all photos – via ArrayController but without a remote service)
/photos/1 ... /photos/2 (shows one photo)
Can anyone offer a best practice?
You have to define a route that matches the url you want:
App.Router.map(function() {
// this will give you ~/#/photos
this.route('photos')
// this will give you ~/#/photos/1 (or whatever number)
this.route('photo', { path: '/photos/:photo_id' });
});
Here's a sample: http://jsfiddle.net/schawaska/AabL8/
If you want to do nested views, like displaying a list of thumbs and when clicking the thumb you see the picture in its actual size underneath the list, then you'll have to do it slightly different by using route resources, nested like this:
App.Router.map(function() {
this.resrouce('photos', function() {
this.route('photo', { path: '/:photo_id' });
});
});
If you do it this way, you'll have to add an {{outlet}} in the "photos" template
and add Photos in the name of the classes that is responsible for a single photo object
PhotoRoute becomes PhotosPhotoRoute
data-template-name="photo" becomes data-template-name="photos/photo"
Here's a sample: http://jsfiddle.net/schawaska/JfRbf/

Backbonejs conditional route for wizard

I'm trying to create a little wizard with backbonejs in which the answers to certain questions determine the path being taken through the wizard. Is there a way in backbonejs to assess the current state of the model and navigate to the next page accordingly? Or is there another way of accomplishing this best in a backbonejs kind of way?
I think the best way is to treat each answer as a different route. That way when the user selects an answer, the route is change and you can load/change views accordingly in your router. Be sure to make use of variables in routes like
routes: {
":question/:answer": "checkAnswer"
}
Where question and answer are variables
Hope this helps
You can have your router subscribe to the model's "change" or "change:[attribute]" event, then change the route and page accordingly
OR whenever you want to go to a new page call the router's navigate function
router.navigate("question1/option1", {trigger: true});
This will change the url and also trigger the route you set up for "question1/option1"
So if your router is:
router = Backbone.Router.extend({
routes: {
"question1/option1": "answer1"
},
answer1: function() {
//change the page / or take whatever other action you want.
}
answer1 function will be called to setup your next page.

Categories