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

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/

Related

Ember not calling setupController of router

So, I have two paths in my route. I created the two routes as the doc recommends.
My router is the following:
// router.js
Router.map(function() {
this.route('photos');
this.route('photo', { path: '/photo/:photo_id' });
});
If I visit firstly the route /photo/ID and then go to /photos, it will only show one object on the latter. (wrong)
If I visit /photos first it shows all the objects and I can go to /photo/ID later on and it will be fine. (right)
I want to make it work both ways. How to do this? You can see my code for each route down below:
// photo.js
export default Ember.Route.extend({
model(params) {
return this.get('store').findRecord('photo', params.photo_id);
}
});
// photos.js
export default Ember.Route.extend({
setupController(controller, model) {
let photos = this.get('store').findAll('photo');
console.log('add all...');
// convert to an array so I can modify it later
photos.then(()=> {
controller.set('photos', photos.toArray());
});
},
});
I can always call the findAll() function regardless where the user goes, but I don't think this is smart.
The way I am dealing with the page transitions:
To go to photos I use:
{{#link-to 'photos'}}All{{/link-to}}
To go to /photo/ID I inject the service '-routing' and I use in one event click like this:
routing: Ember.inject.service('-routing'),
actions() {
selectRow(row) {
this.get("routing").transitionTo('photo', [row.get('id')]);
}
}
findAll will get it from a store and return immediately and later on it will request the server and update the store. but in your case, as you are not using route model hook, so this live array will not be updated so it will not reflect it in the template.
If I visit firstly the route /photo/ID and then go to /photos, it will
only show one object on the latter.
In the above case, store will contain only one reocrd, so when you ask for store data using findAll it will return the existing single record.
Another option is,
avoiding this photos.toArray() - It will break live-array update, I am not sure why do you need it here. since photos is DS.RecordArray.
Note: It's important to note that DS.RecordArray is not a JavaScript
array, it's an object that implements Ember.Enumerable. This is
important because, for example, if you want to retrieve records by
index, the [] notation will not work--you'll have to use
objectAt(index) instead.

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?

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

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

Ember.js does not auto bind model RESTful changes

Correct me if I'm wrong, but I thought Ember should most of the model - view binding for you?
What would be the case when you have to manually track model changes and update/refresh the view accordingly?
The app I'm working have nested routes and models associated with them.
App.Router.map(function() {
this.resource('exams', {path: "/exams"}, function() {
this.resource('exam', {path: ":exam_id"}, function(){
this.resource('questions', {path: "/questions"}, function() {
this.route("question", {path: ":question_id" });
this.route("new");
})
})
});
});
Everything works fine and I'm able to get exams and questions separately from the rest server.
For each model I have appropriate Ember.ArrayController and Ember.ObjectController to deal with list and single model items in the view. Basically for both models the way I handle things is IDENTICAL except for the fact that one is nested within the other. One more difference is that to display the nested route data I'm using another {{outlet}} - the one that is inside the first template.
Now the problem is that the top level model binding to the views is handled automatically by Ember without any special observers, bindings etc.. - e.g. When I add new item it is saved and the list view is refreshed to reflect the change or when the item is deleted it is auto removed from the view. "It just works (c)"
For second model (question), on the other hand, I'm able to reproduce all the crud behaviour and it works fine, but the UI is not updated automatically to reflect the changes.
For instance I had to something like this when adding new entry (the line in question has a comment):
App.QuestionsController = Ember.ArrayController.extend({
needs: ['exam'],
actions: {
create: function () {
var exam_id = this.get('controllers.exam.id')
var title = this.get('newQuestion');
if (!title.trim()) { return; }
var item = this.store.createRecord('question', {
title: title,
exam_id: exam_id
});
item.save();
this.set('newQuestion', '');
this.get('content').pushObject(item); // <-- this somehow important to update the UI
}
}
});
Whereas it was handled for me for (exam model)
What am I doing wrong? How do I get Ember.js to track and bind model and change the UI for me?
With
this.get('content').pushObject(item);
you push your new question to questions controller array. I think it would be better if you push the new question directly to the exam has_many relation.
exam = this.modelFor('exam');
exam.get('questions').pushObject(item);

Categories