Navigate from child to Parent not work - ember.js

In my usecase, I want to navigate from parent route to a child route and from child to parent. The first case work, but the second not. Why? What is wrong? Is the mistake in renderTemplate?
App = Ember.Application.create();
App.Router.map(function() {
this.resource('parent',function(){
this.resource('child',function(){
});
});
});
App.ChildRoute = Ember.Route.extend({
renderTemplate: function(){
this.render('child', {
into: 'application',
controller: 'child'
});
}
});
<script type="text/x-handlebars">
<h1>Ember Sandbox</h1>
<nav>
{{#linkTo 'parent'}} Parent {{/linkTo}}
</nav>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<h2>Welcome</h2>
</script>
<script type="text/x-handlebars" data-template-name="parent">
<h2>Parent</h2>
{{#linkTo 'child'}} Child {{/linkTo}}
</script>
<script type="text/x-handlebars" data-template-name="child">
<h2>Child</h2>
{{#linkTo 'parent'}} Parent {{/linkTo}}
</script>

Whenever you nest a resource, emberjs provides an Index route (App.ParentIndexRoute). When you transition from child resource to parent, the parent template is already rendered and hence it will be redirected to the index route (App.ParentIndexRoute).
Rendering your parent template in App.ParentIndexRoute will solve your problem
App.ParentIndexRoute = Ember.Route.extend({
renderTemplate: function(){
this.render('parent', {into: 'application'});
}
});
Your Working jsbin

Related

Why is #each traverse order reversed when inside a component?

See the jsbin example here
Here is my code:
App = Ember.Application.create();
App.Router.map(function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
App.DerpMenuComponent = Ember.Component.extend({
items: null,
createSteps: function() {
this.set('items', Ember.ArrayProxy.create({content: []}));
}.on('init'),
register: function(item) {
this.get('items').addObject(item);
}
});
App.DerpMenuItemComponent = Ember.Component.extend({
title: null,
register: function() {
this.get('parentView').register(this);
}.on('didInsertElement')
});
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.3.0.js"></script>
<script src="http://builds.emberjs.com/tags/v1.8.0/ember.js"></script>
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" id="index">
{{#derp-menu}}
{{#each item in model}}
{{#derp-menu-item title=item}}
<div style="background: #CCC; color: #00F; margin: 10px; padding: 5px">{{item}}</div>
{{/derp-menu-item}}
{{/each}}
{{/derp-menu}}
</script>
<script type="text/x-handlebars" id="components/derp-menu">
<ul>
{{#each item in items}}
<li>{{item.title}}</li>
{{/each}}
{{yield}}
</ul>
</script>
<script type="text/x-handlebars" id="components/derp-menu-item">
{{yield}}
</script>
I can see, that the derp-menu-elements register in reverse order, when adding them into the template dinamically, using the #each helper. Can anyone please explain why that is the case? If I manually type out the derp-menu-items inside the derp-menu component - everything is displayed correctly, I'm guessing that's because Handlebars somehow act differently in that scenario. Can anyone provide insights into what's happening in both of these cases?
the didInsertElement event always fire from the last/lowest level and then moves up the tree. This is so that when didInsertElement is fired on a parent element you can be sure that all the children are already inserted in the dom.
In your case you are registering with the parent .on('didInsertElement') you are ending up with the elements getting added to the array in the reverse order.
If you changed your code to be based on .on('init') (like below) then they would get be in the same order.
App.DerpMenuItemComponent = Ember.Component.extend({
title: null,
register: function() {
this.get('parentView').register(this);
}.on('init')
});
You can see a working example here: http://emberjs.jsbin.com/hirolu/1/edit?html,js,output

Emberjs template not rendering

I'm trying to understand Ember routing and template rendering with a simple example. I have a page like the following:
<html>
<head>.....</head>
<body>
<script type="text/x-handlebars" data-template-name="cars">
cars<br/>
</script>
<script type="text/x-handlebars" data-template-name="cars/new">
cars new
</script>
<script type="text/x-handlebars">
<header id="header">
{{outlet header}}
</header>
<section id="main">
{{outlet main}}
</section>
<footer id="footer">
Some footer
</footer>
</script>
<!--lib files-->
<!--script will go here-->
</body>
</html>
Throughout the application, all contents need to be entered in the main outlet. I have a javascript file with the following contents:
window.App = Ember.Application.create();
App.Router.map(function() {
this.resource("cars",function (){
this.route("new");
});
});
App.ApplicationAdapter = DS.FixtureAdapter.extend();
App.CarsRoute = Ember.Route.extend({
renderTemplate: function() {
this.render({ outlet: 'main' });
}
});
App.CarsNewRoute = Ember.Route.extend({
renderTemplate: function() {
this.render({ outlet: 'main' });
}
});
The problem is that cars template is properly being rendered while cars/new isn't. How can I correct this issue ?
Not sure all the outlets are necessary--but I think the simplest change that can get you running is to change
<script type="text/x-handlebars" data-template-name="cars">
to
<script type="text/x-handlebars" data-template-name="cars/index">
and add
<script type="text/x-handlebars" data-template-name="cars">
{{outlet}}
</script>
The issue is that it's using cars template as the parent template for cars/index and cars/new. Ember will try to render cars/new into an outlet, but you haven't specified one in cars. Ember will figure out how to make it happen if you omit the cars template, but not without a notice in your console.
tWhen you explicitly tell a route to render in a specific outlet, I believe you need to disconnect from that outlet before something new can be rendered in it. Especially if the new route is a child of the existing route in that outlet.
Typically you will want to render cars into a generic {{outlet}} and cars/new should render into another {{outlet}} within the cars template.
If you want to continue doing this the way you want, you will need to call disconnectOutlet() in an action like willTransition() before the new template can be rendered. But I can imagine that would get confusing fast.
for what it's worth, this is how i would attempt it.
renderTemplate: function() {
this.render({
into: 'application',
outlet: 'main'
});
},
actions: {
willTransition: function() {
this.disconnectOutlet({
outlet: 'main',
parentView: 'application'
});
}
}
some other things to consider:
if an error were to occur, ember would not automatically switch to a substate. you would also need to explicitly define the errors route to do this... same thing for loading substates... and literally every route in your app would need to connect and disconnnect from the main outlet

Template doesn't render into named outlet

I'm trying to create several pages that will use the same menu so that I can save the state of the menu easily and avoid code duplication. My problem is that the menu template doesn't render in the menu outlet of the pages.
Here is the code :
App.Router.map(function() {
// put your routes here
this.resource('profil', function() {
this.route('news');
this.route('menu');
});
});
App.MenuRoute = Ember.Route.extend({
renderTemplate: function() {
this.render({
into: 'profil/news',
outlet: 'menu',
});
}
});
And in index.html I have :
<script type="text/x-handlebars" id="profil/news">
...
{{outlet}}
{{outlet menu}}
</script>
<script type="text/x-handlebars" id="menu">
...
</script>
The template 'profil/news' is rendered but the template 'menu' is not rendered at all : it should be rendered inside 'profil/news' when I visit profil/news . Any idea ?
Thank you
The problem was that I needed to use :
<script type="text/x-handlebars" id="profil/news">
...
{{outlet}}
{{render 'profil/menu'}}
</script>
And to change the name of the handlebar to match the routing:
<script type="text/x-handlebars" id="profil/menu">
Moreover, the statement beginning with App.Menuroute is unnecessary and be removed.
Now everything is working as expected.

Is "basic" a reserved route name in Ember?

I have a route in an Ember app called "basic" corresponding to the name of an API endpoint.
This route doesn't work - links to it don't render its template.
Here's a JSBin demonstrating the failure: http://emberjs.jsbin.com/hisoxadi/1
JS:
App = Ember.Application.create();
App.Router.map(function() {
this.route('basic');
this.route('test');
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
Templates:
<script type="text/x-handlebars">
<h2> Welcome to Ember.js</h2>
{{#link-to 'index'}}Index{{/link-to}}
{{#link-to 'basic'}}Basic Route{{/link-to}}
{{#link-to 'test'}}Test Route{{/link-to}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="basic">
basic route is here
</script>
<script type="text/x-handlebars" data-template-name="test">
test route is here
</script>
<script type="text/x-handlebars" data-template-name="index">
<ul>
{{#each item in model}}
<li>{{item}}</li>
{{/each}}
</ul>
</script>
To expand on your comment a bit, basic is indeed a reserved word. Specifically, it's a reserved word for the resolver. You can see the source here.
useRouterNaming: function(parsedName) {
parsedName.name = parsedName.name.replace(/\./g, '_');
if (parsedName.name === 'basic') {
parsedName.name = '';
}
},
And because of the way that Ember.js sometimes looks up routes and controllers in the container, it's a fair bet to say that there's no way around this without major code changes. There should probably be a documentation issue filed for this.
EDIT: I created an issue for this here.

How to use application model inside partial of route?

I think this should be a really easy fix, i just cant figure it out.
I have this model in my ApplicationRoute:
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return {
sideNav: data.side,
breadcrumbs: Util.breadcrumbs()
}
}
});
application template:
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
overview template:
<script type="text/x-handlebars" data-template-name="overview">
{{partial side}}
</script>
_side partial:
<script type="text/x-handlebars" id="_side">
{{#each model.side}}
<i {{bindAttr class="iconClass"}}></i><p>{{label}}</p>
{{/each}}
</script>
When I load my overview route, the stuff in there loads, but the application model is not applied to the side partial like I would like it to be... there may be a better way to do this. Thanks!
It looks like you have two problems:
You are binding to side instead of sideNav inside your partial.
You're trying to access the model of ApplicationRoute inside of the overview template (which presumably has its own route and controller)
Partials don't change context, so they don't add any complexity on their own. For instance, if we restrict ourselves to the application template, the following will work:
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return {
foo: 'bar'
};
}
});
<script type="text/x-handlebars" data-template-name="application">
{{partial partial}}
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="_partial">
{{foo}}
</script>
However, if you want to get at the application model inside of a nested route, you'll need to ask for it. For example, inside of the (default) index route, you could add the following:
App.IndexRoute = Ember.Route.extend({
model: function() {
return this.modelFor('application');
}
});
<script type="text/x-handlebars" data-template-name="index">
{{partial partial}}
</script>
You can see both examples in this jsfiddle.