Ember pre4 - nested routes - ember.js

I'm trying to understand how to use nested routes.
My code:
App.Router.map(function() {
this.route("site", { path: "/" });
this.route("about", { path: "/about" });
this.resource("team", {path:'/team'}, function(){
this.resource('bob',{path:'/bob'});
});
});
And I'm trying to get to the Bob page with:
{{#linkTo 'bob'}}bob{{/linkTo}}
What am I missing?
jsbin
Thanks.

try instead
{{#linkTo 'team.bob'}}bob{{/linkTo}}
Between you can simplify your router map this way - you only need to specify the path if it's different from the route name.
App.Router.map(function() {
this.route("site", { path: "/" });
this.route("about");
this.resource("team", function(){
this.route('bob');
});
});
UPDATE
See a working example here
In summary, You need to provide an implementation of the renderTemplate function of TeamBobRoute where you explicitly specify where you want to render your template bob. Using the render option into you can override the default behaviour, rendering to the parent outlet, and pick which parent template to render to
App.TeamBobRoute = Ember.Route.extend({
renderTemplate:function(){
this.render('bob',{
into:'application',
});
}
});
<script type="text/x-handlebars" data-template-name="site-template">
This is the site template
{{#linkTo 'about'}}about{{/linkTo}}
{{#linkTo 'team'}}team{{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="about">
This is the about page
</script>
<script type="text/x-handlebars" data-template-name="team">
This is the team page
{{#linkTo 'team.bob'}}bob{{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="bob">
This is the bob page
</script>
<script type="text/x-handlebars">
This is the application template
{{outlet}}
</script>
FYI the render method supports the following options: into, outlet and controller as described below.
The name of the PostRoute, as defined by the router, is post.
By default, render will:
render the post template
with the post view (PostView) for event handling, if one exists
and the post controller (PostController), if one exists
into the main outlet of the application template
You can override this behavior:
App.PostRoute = App.Route.extend({
renderTemplate: function() {
this.render('myPost', { // the template to render
into: 'index', // the template to render into
outlet: 'detail', // the name of the outlet in that template
controller: 'blogPost' // the controller to use for the template
});
}
});
If you had a named template inside your application template then you would target it this way
App.TeamBobRoute = Ember.Route.extend({
renderTemplate:function(){
this.render('bob',{
into:'application',
outlet:'team-member',
});
}
});
<script type="text/x-handlebars">
This is the application template
{{outlet 'team-member'}}
{{outlet}}
</script>

You're missing the outlet in the team page. The template should look like this.
<script type="text/x-handlebars" data-template-name="team">
This is the team page
{{#linkTo 'bob'}}bob{{/linkTo}}
{{outlet}}
</script>
Each route is rendered into it's parent's template's outlet.
so when you go into "team", then "team" is rendered into the "application" outlet.
When you go to "bob", the "bob" template is rendered into the "team" outlet.
This can be overridden, but is the default behavior.
Also, each parent resources gives you two model/controller/view/template sets. So when you define:
this.resource('team',{path:'/team'});
You get the "team" template and the "team-index" template.
the "team" template is where stuff that is shared between child routes goes (this is why it needs to have the outlet) and the "team-index" template is where stuff that is specific to your "team index" would go.

Related

Ember.js Rendering default content to a nested outlet

How do I render default content into a nested outlet?
For example, if I have an index template such as this:
<script type="text/x-handlebars" id="index">
<div>{{outlet}}</div>
</script>
<script type="text/x-handlebars" id="photo">
Photo!
</script>
<script type="text/x-handlebars" id="default">
Default photo
</script>
And a nested routes:
App.Router.map(function() {
this.resource('index', { path: '/'}, function() {
this.resource('default');
this.resource('photo', { path: ':id' });
});
});
That works fine when I use to link-to helper to load the page into the outlet. However, I cannot work out how to render default content into the outlet when the page first loads.
If I do something like this:
App.IndexRoute = Ember.Route.extend({
renderTemplate: function(controller, model) {
this._super(controller, model);
this.render('default');
},
});
It renders the default content into the main outlet. If I try to specify a named outlet instead:
this.render('default', { outlet: 'centre' });
I get the following error message:
Error while processing route: index.index Assertion Failed: An outlet (centre) was specified but was not found. Error: Assertion Failed: An outlet (centre) was specified but was not found.
Even when using a named outlet:
{{outlet "centre"}}
Any help appreciated.
Remove the index resource, it's already created for you and will make things confusing. Also, if you're needing to hook renderTemplate this early in the game, you're probably not following Ember's conventions.
I would also suggest removing the default resource, as Ember provides that by way of index. The top template is application.hbs, which essentially just has an {{outlet}} in it. So in summary:
Delete the index template
Change id="default" to id="index"
Remove the index resource from your router map
Thanks everyone, I used oshikryu's solution.
Templates:
<script type="text/x-handlebars" id="index">
<div>{{outlet}}</div>
</script>
<script type="text/x-handlebars" id="photo">
Photo!
</script>
<script type="text/x-handlebars" id="default">
Default photo
</script>
JavaScript:
App.Router.map(function() {
this.resource('index', { path: '/'}, function() {
this.resource('photo', { path: ':id' });
});
});
App.IndexIndexRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('default');
}
});

Ember js version 1: Route hierarchy / activation

We have a scenario along these lines:
Quote
--->Create
So route names quote and quote.create.
The issue is that we need to render the templates into the main outlet. So in our main route (that all other are inherited from) we have this:
renderTemplate: function() {
this.render({ into: 'application' });
}
When I navigate to quote it renders the quote view. From there I navigate to quote.create and it renders the create view. However, going back to quote from quote.create renders nothing.
How can I get around this?
When I go back to the \quote url route 'quote.index' is sought. Since it is defined 'automagically' nothing happens. When I define the route explicitly ember tries to find the quote.index template and view and these do not exist.
A workaround I tried is to have this:
App.QuoteIndex{Route|Controller|View} = App.Quote{Route|Controller|View}.extend()
EDIT:
Hey diddle-diddle, here is my fiddle :) http://jsfiddle.net/EbenRoux/Mf5Dj/2/
Ember.js does not rerender a parent view when transitioning to a parent route, so using into with a parent view template is not recommended.
There is an easier way to create what you are trying to: use a quote/index route:
<script type="text/x-handlebars" data-template-name="application">
<h1>Rendering Issue</h1>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="quote">
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="quote/index">
<h2>Quote View</h2>
{{#linkTo 'quote.create'}}Create a new quote{{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="quote/create">
<h2>Quote Create View</h2>
<p>Some controls would go here.</p>
{{#linkTo 'quote'}}Go back to quote view{{/linkTo}}
</script>
App = Ember.Application.create({});
App.ApplicationRoute = Ember.Route.extend({
activate: function () {
this.transitionTo('quote');
}
});
App.Router.map(function () {
this.resource('quote', function () {
this.route('create');
});
});
See http://jsfiddle.net/eYYnz/

Ember: controller properties not available in partial views - what am I doing wrong?

See JSFiddle: http://jsfiddle.net/cyclomarc/aYmuJ/3/
I set a property in the application controller and want to display this property in a partial view. This does not seem to work. I can access the property in the template itself, but not in the partial view rendered within the template ..
index.html
<script type="text/x-handlebars">
<h3>Ember access to controller properties</h3>
{{#linkTo 'about'}}About{{/linkTo}} <br><br>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="about">
Access to property in index template: <br>
<b>{{controllers.application.applicationVersion}}</b>
<br><br>
{{render "_footer"}}
</script>
<script type="text/x-handlebars" data-template-name="_footer">
Footer text (partial view) with a controller property:<br>
<b>{{controllers.application.applicationVersion}} MISSING</b>
</script>
app.js
var App = Ember.Application.create({});
App.Router.map(function () {
this.resource('about', { path: "/about" });
});
App.IndexRoute = Ember.Route.extend({
redirect: function () {
this.transitionTo('about');
}
});
App.ApplicationController = Ember.Controller.extend({
//Set some properties
applicationVersion: "1.0.0"
});
App.AboutController = Ember.Controller.extend({
needs: "application"
});
render view helper have your own context.
To use the current context in a other template use the partial view helper.
{{partial "footer"}}
When you use render a new controller is created, in that case named generated _footer controller.
Using partial will preserve the controller bound to the template that called the partial template
And since you used needs in about controller, you don't have it in the new generated controller.
Here is a sample

Template associated with nested route not rendering in parent template

Here are my HTML templates:
<script type="text/x-handlebars">
<p>Application template</p>
{{#linkTo employees}}<button>Show employees</button>{{/linkTo}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="employees">
<p>Employees template</p>
{{#linkTo employees.employee}}<button>Show employee</button>{{/linkTo}}
{{outlet employeeOutlet}}
</script>
<script type="text/x-handlebars" data-template-name="employee">
<p>Employee template</p>
</script>
Here is the javascript:
App = Ember.Application.create();
App.Router.map(function () {
this.resource('employees', function () {
this.route('employee');
});
});
App.EmployeeRoute = Ember.Route.extend({
renderTemplate: function() {
this.render('employee', { // the template to render
into: 'employees', // the template to render into
outlet: 'employeeOutlet', // the name of the outlet in that template
controller: 'employee' // the controller to use for the template
});
}
});
JS Bin here
I added a lot of unnecessary code in order to try to get the employee template to render in the outlet of the employees template (e.g., naming the outlet, defining the renderTemplate method...), but it doesn't seem to work.
What am I doing wrong here?
You need to name the employee template to employees/employee and it will work. Otherwise you need to tell the view to use the employee template.
example
http://jsbin.com/ukajix/1/

How to render multiple templates for a route in Router v2

my index template has two outlets, one for header, another for content. the template rendered in the content changes depending on the content being viewed.
In the old router, this could be done by calling connectOutlet on different controllers who owned that template. I can't figure out how to do the same in the new router.
any suggestions?
With my research, I came to this:
Say you have a router defined like this:
App.Router.map(function(match) {
match('/').to('index');
});
ApplicationTemplate:
<script type="text/x-handlebars">
{{outlet header}}
{{outlet}}
</script>
IndexTemplate:
<script type="text/x-handlebars" data-template-name="index">
{{outlet dashboard}}
{{outlet spaces}}
</script>
Now, What we want is that when user goes to the index router, the page should:
Render index into main outlet and header into header outlet of application template.
render dashboard, spaces template into Index Template.
To achieve this, we write the following code in indexRoute
App.IndexRoute = Em.Route.extend({
renderTemplate: function(controller, model){
//Render header into header outlet
this.render('header',{
outlet:'header'
});
//Render index into main outlet. If you comment out
//this line, the code below fails
this.render('index');
//by using into, we can render into the index template
//Note: The controller is optional.if not specified,
//ember picks up controller for the given template.
this.render('dashboard',{
outlet:'dashboard',
into:'index',
controller:this.controllerFor('somethingElse', App.TestModel.find())
});
//controller is SpacesController
this.render('spaces',{
outlet:'spaces',
into:'index'
});
}
});
you can use the renderTemplates function in the router to render mulitple views to name outlets:
renderTemplates:function () {
this.render('todos_list', {
into:'todos', //template name
outlet: 'todos', //named outlet
controller: 'listController' //controller you want to use
});
this.render('todos_test', {
into:'todos',
outlet: 'test',
controller: 'testController'
});
},
setupControllers:function (controller, model) {
this.controllerFor('list').set('content', listmodel.find());
this.controllerFor('test').set('content', testmodel.find());
}
The setupControllerControllerFor function will allow you to assign what we set as 'context' in the previous router.
In your template, you would name outlets just as before:
{{outlet list}}
{{outlet test}}
Hope this helps :)