IS there any way for me not to extend the application template in Emberjs? As in I have one route that the url needs to be /questions for SEO purposes but it has a completely different design than all the other pages. So I don't want it to inherit the application template. Is this possible?
You have two options I can think of. The first is that proposed in a comment: create separate top-level routes for questions and everything else:
// templates/application.js
{{outlet}}
// templates/questions.js
{{! whatever you want for the questions template }}
// templates/base.js
{{! base template stuff, headers, nav bars, content, etc. }}
// router.js
Router.map({
this.route('questions');
this.resource('base', function() {
this.route('base1');
....
});
});
The comment that this will result in routes of the form /base/base1 is not correct. By using this.resource, the routes will be of the form /base1.
Using outlets
There is another approach that may or not meet your needs. It involves putting a custom outlet in the application template, that may be filled in by subroutes. Then define a superclass for "regular routes" which define a renderTemplate which renders the header matter into that outlet.
// templates/application.js
{{outlet name='header'}}
{{outlet name='main'}}
// mixins/normal-route.js
renderTemplate() {
this.render('header', {
outlet: 'header'
});
}
// router.js
Router.map({
this.route('questions');
this.route('base1');
});
// pods/base1/route.js
export default NormalRoute.extend({...
This has the benefit of allowing the application template to be more "readable" and semantic, in that it explicitly shows that it is composed of a (possible) header portion, filled in some other components, and a "main" portion.
Related
Within one of my route's renderTemplate method, I've tried to render a different template by using this.render:
App.IndexRoute = Ember.Route.extend({
renderTemplate: function() {
this.render( 'dashboard', {
into: 'admin'
});
}
});
But the application within the browser is empty and the console shows the following:
Assertion Failed: You attempted to render into 'admin' but it was not
found
After this error message, I thought that the "admin" template might simply not be existent, but it it's there. Both the "dashboard" and the "admin" template are loaded. And the weirdest thing: I'm able to use this.render( 'dashboard' ) and this.render( 'admin' ) and both of them work fine.
What am I doing wrong? I've even added an {{outlet}} tag to the "admin" template.
If you want to render into admin then you have to use named outled inside your template (associated with route file you write renderTemplate). So, inside your template use:
{{outlet 'admin'}}
edit
I'm not really sure what to do right now. Just to clarify: "admin" is
a hbs template which contains a {{outlet}}. And into this outlet tag,
I want to load 'dashboard.hbs'. And after that, I want to output the
whole thing.So in which file do I need
I'm assuming you want to render these 2 templates from another unassociated route. In that case you could add {{partial 'dashboard'}} to admin.hbs and use just this.render('admin') in your IndexRoute.
edit 2
Inside your IndexController specify partialName: 'dashboard' and change it dynamically in your code and replace {{partial 'dashboard'}} with {{partial partialName}}. It should work dynamically and you can swap out dashboard for another templates.
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'd like to make modal dialog boxes into a separate state within Angular UI Router. However, I have a case where the modal box can/should appear on top of all states... and I am not sure if this is possible.
So for example, let's say I have /store and /admin as 2 separate top-level states. Now imagine that I have a modal dialog that is unrelated, like a contact form (just as an example) that should go on top of each.
If I model this as /contact, the /store or /admin states are obviously forgotten, so the background behind the modal is blank.
The solution might be to have two child states, like /store/contact and /admin/contact, and this preserves the content behind the modal dialog box... however, this approach does not scale for X number of top-level states.
In a nutshell, how can I say that /contact is a child of all states, regardless of nesting? Is this possible? Or do I simply have to not use angular UI router in this case?
The UI-Router state machine is expressed with parent-child relations. So the answer is - each child can have just/exactly one Parent. That's a fact. And it could be treated as "kind of not working answer".
But, in case that we really would like to have many child states /contact (where contact feature is moved to its own state), I would not say that repeating of definition is an issue.
It could be marked as overhead, but state is just a configuration. It does not affect the performance so much. The views and controllers are instantiated per state anyhow... regardless of its state def.
// declare once view
var contactState = {
controller: ...
template: ...
...
};
// reuse as need for some ...
stateNamesWithContact.forEach( function(stateName)
{
// regiester state many times as "some.parnet.child.contact"
$stateProvider
.state(stateName + ".contact", contact);
...
Another approach, which I would perfer, is to NOT use Contact as a substate. Move it into view (which functionality will support modals)
Multiple Named Views
Defined once, in root state - as a view
In case, that Contact view/controller are static, we can just hook them into supper root state:
.state("root", {
views : {
"" : {
template: "<ui-view />" // here will be injected all children
}
"contact#" : {
... //setting of the Contact view / controller
}
}
}
Now, each "parent" state can profit from the above, without having affected url or name (no need to have "root.someParent" if parent setting is used)
.state("someState", {
parent: "root"
...
I'm trying to wrap my head around Ember at the moment, but all the magic is making this difficult.
I've set LOG_TRANSITIONS: true and Ember.LOG_BINDINGS = true; which gives me some minimal logging to the console, but I really need more than that.
I'm particularly struggling with seeing what's going on when Ember is automagically creating Controllers, Views and Templates.
Is there a way to log this aspect of the framework - to see where Ember is looking for Templates/Views/Controllers and when it is creating one on its own volition.
For example, I have the following routes set up:
App.Router.map(function() {
this.route("example_items", {path: "/"});
});
with:
App.ExampleItemsRoute = Ember.Route.extend({
model: function() {
return App.ExampleItem.find();
}
});
Ember renders my ApplicationController and its application.handlebars template:
<header class="page-header">
<h1>Application Template</h1>
</header>
{{outlet}}
But fails to render my example_items.handlebars template. I get no exception or warning, and if I check the DOM, I can see ember has created a generic view in its place.
The bindings logging shows me that Ember has transitioned to example_items, but it seems it hasn't used either my ExampleItemsController, ExampleItemsView or template.
How can I debug a situation like this if I receive no errors or messages?
Edit:
App.ExampleItems View:
App.ExampleItemsView = Ember.CollectionView.extend({
templateName: 'example_items'
});
And App.ExampleItemsController:
App.ExampleItemsController = Ember.ArrayController.extend({
});
I'm particularly struggling with seeing what's going on when Ember is automagically creating Controllers, Views and Templates.
Is there a way to log this aspect of the framework - to see where Ember is looking for Templates/Views/Controllers and when it is creating one on its own volition.
Yes. With the latest ember you can now LOG_ACTIVE_GENERATION to see console.log output whenever ember generates something for you.
Another new setting that might be helpful is LOG_VIEW_LOOKUPS
Here's your problem: CollectionView won't use your template. It takes an array as its content property (usually set up as a binding to the controller) and creates childViews manually. Without a content set it'll appear as a blank view.
If you add classNames: ['my-view'] to your view definition, you should see that the view it's instantiating and inserting is actually your view class, just empty. Add contentBinding: 'controller' and it should render itemViews for each item in the array, as well.
As an example, one particular application state may have a home view that just renders some background container,
App.EditView = Ember.View.extend({
templateName: 'edit-template',
})
App.EditController = Ember.ObjectController.extend({
title: 'Edit state',
})
Which are instantiated when I navigate to this state:
App.editRouter = Ember.Route.extend({
route: '/edit',
connectOutlets: function( router, context ){
router.get('applicationController').connectOutlet( 'mainOutlet', 'edit' )
}
})
Once here, the user may manually declare new div elements which map to new view and controller ( and model but that's no super relevant here ), the new div may or may not be a child of the div rendered by editView.
The current way I'm doing it
App.smallView1 = App.SmallView.create({
controller: App.smallController1
}).append()
App.smallController1 = App.SmallController.create()
As you see, nothing here indicates under what state are the view and controller declared.
What I'm confused about:
What is the relationship between this view-controller pair and the instance of EditView and EditController?
What is the relationship between the pair and the editRouter?
Should there be dependancies that need to explicitly specified?
This view-controller pair doesn't seem to be used by the router, so you'd have to create a route for them and connect the outlet with your view-controller pair, unless you want to append this view to an element that won't change per route. It also doesn't have any relationship with the other view-controller pair.
As for your questions:
What is the relationship between this view-controller pair and the
instance of EditView and EditController?
A: The code, as it stands, presents no direct relationship between the small view and controller with edit view and controller, but the difference is that the pair EditView and EditController are not "created", but "given" to the application, which will take care of instantiating that type when required through its own initialization logic (initialize) or when creating the instance of a view when it's required. The pair smallView1 and smallController1 will probably not be good for the router as their instance names end with "1" and I'm not sure if Ember expects that, but anyway, these are being instantiated and directly attached to the application as "living" objects, which is not required when using the router. Does this answer your question?
What is the relationship between the pair and the editRouter?
A: In your code, editRouter is the definition of what state (since Route extends State) your application is when you are on that route; this means that the framework understands that when you are on a given state you need some specific things to occur, for example, loading the view that state requires, loading the data that view should display, etc... this is done through connectOutlet, so for this particular route you don't have any relationship of any kind with smallView1 or smallController1 unless you use a different signature of connectOutlet to specify the viewClass and controller manually.
Should there be dependancies that need to explicitly specified?
A: Yes. When using the Router, your application must have a controller named ApplicationController, and when you call connectOutlet, the name you pass must be corresponding to one view and controller (I think the controller might not me required, but I'm not sure at the moment). So if you say connectOutlet('about'), the framework will look for a view named AboutView as per convention, then will instantiate this view and render on the appropriate outlet in the container view.
How will the controller access the router if it needs to?
A: At any point in your application you can access the router with App.router assuming your application is named "App" and your router was named "Router", so in any of your methods in your controller you can, for example, use the router to transition: App.router.transitionTo('root.index.home').