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');
}
});
Related
I am new to ember and I am building a DnD character sheet to learn and practice. Right now I am having a lot of trouble getting access to model data in a controller. After hours and hours of reading related posts it is just not clicking and I think I am misunderstanding what I am passing to the controller.
Basically what I am trying to do is grab data from a model so I can do calculations on them and then display the results of those calculations on the page.
Here is my transforms/router.js:
Router.map(function() {
this.route('characters', { path: '/'})
this.route('new', {path: 'new'});
this.route('view', {path: '/:character_id'});
});
So here I am trying to pull up the view page which has the URL of the character id. Next here is my route for the view page:
export default Route.extend({
character: function () {
return this.store.findRecord('character', id)
}
});
So this is finding the record of the character with the id I pass. My link looks like this and is coming from a component:
<h5 class="card-title">{{#link-to 'view' id}}{{name}}{{/link-to}}</h5>
Now I have my controller for the view page, which looks like this:
init(id){
let character = this.get('character')
}
When I try to log character, it is still undefined. When looking ember information in dev tools it seems the page is getting the information from the model after I refresh the page, but I just can't seem to be figure out how to grab that info in the controller itself to manipulate it.
I've been trying to figure this out for quite a while now, and its getting pretty frustrating. I currently have a work around where I do the calculations beforehand and just store all the calculated results in the model as well, but while I am learning I would like to understand how this works. Thanks is advance.
Edit: As pointed out in comments below I was missing let when defining character.
Your model hook seems wrong. You're using id but never define it. Probably what you want is more like this:
character(params) {
return this.store.findRecord('character', params.character_id);
}
Next your init hook makes no sense:
init(id){
let character = this.get('character')
}
First there is no id passed to the init hook. Second you're missing this._super(...arguments) which should always be called when you override init.
Last is that your controller is first created and later populated with the model. Also the model is populated as model property, not character.
So you could place this in your routes template and it will work:
This is character {{model.id}}
Or if you want to change something before you pass it to the template you should use a computed property in your controller:
foo: computed('model.id', function() {
return this.get('model.id') + ' is the id of the character';
}),
However for this code to run you need to use. The easiest way to use it is to put it into your template:
{{foo}}
My goal is to dynamically create a navigation menu on a Meteor website.
I have a classic menu with static links and the yield where I want the other links to be inserted when needed :
<nav id="menu">
Link 1
Link 2
{{> yield "navLinks"}}
</nav>
-
// module_posts.js
Router.onAfterAction(function(){
if (userIsAdmin()) {
this.render('postsMenu', { to: 'navLinks' });
}
});
// module_users.js
Router.onAfterAction(function(){
if (userIsAdmin()) {
this.render('usersMenu', { to: 'navLinks' });
}
});
The problem is for example, when an admin is connected, each module (posts, roles, categories...) should insert its own links into that region, but what happens is that each module is rendering over the previous one and removing the links added by another module, so the region seems to only accept one template to be rendered in.
Maybe I am doing it wrong, so please give me a clean solution.
-- EDIT --
Okay, maybe a better explanation :
I have several modules (posts, users, roles, etc) that can be enabled or disabled, each of them has a navigation menu to manage it.
Now I want to display their menu in one unique region named {{nav}}.
So I would have to write code somewhere in each module to append their menu in the {{nav}} region if the module is enabled.
I really want to use templates to do that because I could build logics directly into them instead of using collections to store links.
The reason why you are seeing the issue that you are is because of the fact that you are using the Router.onAfterAction() function to render your menu templates. The problem with this is that the Router.onAfterAction() function applies globally to all routes and runs whenever a new route is run. This is why you are only seeing the navigation links from the final defined navigation links definition, which in the case of your question above would be the usersMenu navigation links. Instead, you want to define your navigation menu template rendering logic for each route that you want it to differ on. Also, you do not want to use the onAfterAction() function, because this is intended to be used for post-processing once your route has actually been run. In order to achieve what you would like, you would do the following:
Router.route('/admin/posts', {
...
yieldRegions: {
'postsMenu': {to: 'navLinks'}
}
...
});
Router.route('/admin/users', {
...
yieldRegions: {
'usersMenu': {to: 'navLinks'}
}
...
});
So, as you can see, we have defined a route definition for each of your unique routes as specified in your question, one for admin posts and one for admin users. In order to specify specific templates to be rendered into named yields for a given route, you should use the yieldRegions route option. In it, you specify the name of each template that you would like to render into which named yield region. This is where you specify your templates from your question.
If you would like to read about all of the route specific options that are available when defining a route definition, please take a look here.
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
please see this functioning JSBin: http://jsbin.com/acUm/20
Here is the behavior I am working on. If I type 'Monroe' to filter the list down and then hit the browser back button, I expect Ember to process the route and fire the request for all patients. Instead it appears to do nothing. This is especially confounding since the back button seems to work in other areas.
Perhaps I have set up this transition improperly? Or is this an Ember.js bug?
When you transition to a route, it's a good idea to use the childest route in the hierarchy.
In your case you have this:
this.resource('patients', { path: '/' }, function() {
// this is created for you
// this.route('index');
this.route('filtered', { path: '/filtered/:last_name' });
});
By default is created a route index for that resource, so you have the patients.index.
But your transition goes to patients and it isn't the childest.
So to correct this, I have changed your sample to use PatientsIndex[Controller,Router etc], instead of Patients[Controller,Router etc].
Working demo http://jsbin.com/acUm/24/edit
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/