How to render nested route in new page Ember js? - ember.js

I currently trying use LinkTo to render another nested route by using {{outlet}} tag to another new page.
I have a forum route and nested forum details route
In the forum template:
<LinkTo #route="main.forum.forum-details" #model={{post}}>{{post.title}}</LinkTo>
{{outlet}}
As the image above. The nested route will be render at the bottom instead of to the new page. How am i going to render it to new page? I was thinking LinkTo will actually link it to the new page right? And the forum details should be render at the {{outlet}} tag, so where should I place the {{outlet}} tag in order to let it render to new page?

You problem is that you need to understand nested routes.
If your route is main.forum.forum-details this means your router looks like this:
this.route('main', function() {
this.route('forum', function() {
this.route('forum-details');
});
});
So the forum route is a parent route of the forum-details route.
And its important to understand that parent routes are always visible when visiting a child route.
So for the main.forum.forum-details ember will render your application route and inside its {{outlet}} it will render the forum route and inside this {{outlet}} it will render the forum-details route.
So if you want either the forum or the forum-details route you can restructure your routes:
this.route('main', function() {
this.route('forum');
this.route('forum-details');
});
or you can move what you currently have in your forum route to your forum.index route. If a route has subroutes and none of the subroutes is active there will always be an index route active that you can use.

Related

How do you create nested dynamic routes with ember.js where child route replaces parent's template?

On Ember 3.15 (Octane)
I'm trying to create the following routes in my application
/cars
/cars/:car_id
/cars/:car_id/:model_id
The first two are fine and I've been able to create them using ember-cli
ember g route cars
ember g route cars/car
The problem with the third one is that I need the model template to be shown under the cars template, ie. replace the car template. So if I put an {{outlet}} on the car template, the model template is rendered in it fine but obviously with that {{outlet}} nothing happens when I navigate to /cars/5/2
My router looks like this
Router.map(function() {
this.route('cars', function(){
this.route('car', { path: ':car_id'}, function() {
this.route('model', { path: ':model_id' });
});
});
});
I've tried using an index route ember g route cars/car/index but the problem with this that the params are not available in the index route and can only be accessed on the car route.
As plan b I've created the car and model routes as top level routes (based on this answer), but I'd like to achieve the above because of a few reasons
it seems more logical ie, structuring the app based on the nesting of the routes
I have many nested routes and creating all of them as first level routes will become hard to maintain
ember doesn't apply the active class correctly with this configuration. For example if I have a navbar with Cars as an link, I'd want it to have the active styling on all three pages. But this doesn't work anymore because the second route will be called something like car and the third one something like model.
there are some issues with the urls that are created by default using <LinkTo />.
So if I have something like this in my car template
<ul>
{{#each #model.models as |model|}}
<li><LinkTo #route="model" #model={{model}}> {{model.title}} </LinkTo></li>
{{/each}}
</ul>
The actual link works properly in that it takes me to the correct model page, however, the url is shown as /cars/undefined/undefined. (Although this is fixable by passing #models={{array #model.id model.id}}, it seems like a workaround at this point)
The solution is indeed to use the index route.
So have cars.car.index and cars.car.model. However you should use the cars.car route to load the common car model. Then you can access it in the cars.car.index route with this.modelFor('cars.car').
Then you can access the params.car_id in the cars.car route, use it to load the car, and then access this car from the cars.car.index and cars.car.model routes with modelFor.

Override application.hbs template in Emberjs

In emberjs, I am in a situation that my application already has routes template that uses the application.hbs template, but now I want to create a new route templates that doesn't use application.hbs.
Is there any easy solution for that?
I have seen many answers but that doesn't match my specification and also my version of ember is 2.11.
Thank you.
Keep application.hbs as minimal and common across all routes as you can. What you shoud do is generate top level routes for your application.
Say you have a common setup where you have an authenticated section, post login, and a login section. It is common for pre and post login to have differing top level templates. Try something like this:
ember g route login
ember g route login/index
ember g route login/forgot-password
ember g route authenticated
ember g route authenticated/index
ember g route authenticated/profile
etc...
Your login.hbs would have its own style, and potentially child routes, which will assume that style and place subsequent nested templates in the {{outlet}} that others have mentioned.
File Structure:
routes/
-login/
----index.hbs
----forgot-password.hbs
-authenticated/
----index.hbs
----profile.hbs
login.hbs
authenticated.hbs
application.hbs
In the example above, login.hbs might look like this:
{{yellow-navbar}}
{{outlet}}
and authenticated.hbs like this:
{{pink-navbar}}
{{user.name}}
{{outlet}}
Now, the login/index.hbs and login/forgot-password.hbs templates will render in the login.hbs outlet. both of these pages will render a yellow navbar, and then their own content.
Because authenticated.hbs is another top level parent route, both authenticated/index.hbs and authenticated/profile.hbs will render their content beneath a pink navbar and a display of the current user's name.
if your application.hbs looked like this:
{{#general-site-container}}
<h2>Website Name</h2>
{{outlet}}
{{/general-site-container}}
Then all of the routes, both authenticated and login, will be in the general-site-container, and will all show the h2 with the website name.
An important note in this, and something that I see a lot of people get confused with, is that this folder structure does not dictate the actual path of the route.
The router might be configured like this, to avoid showing "authenticated" in the url:
Router.js
// login.index route assumed at root url /login
this.route('login', { path: '/login' }, function() {
// avail at /login/forgot-password
this.route('forgot-password', { path: '/forgot-password' }
});
//authenticated.index.hbs assumed at root avail at /
//notice that the authenticated parent route has a route of "/"
this.route('authenticated', { path: '/' }, function() {
// authenticated.profile route avail at /profile
this.route('profile', { path: '/profile' });
// as an exmaple you can further nest content to your desire
// if for instance your profile personal info section has a parent
// template/route
this.route('', { path: '/personal-info' }, function() {
this.route('address', { path: '/address' }); //profile/personal-info/address
});
});
i think you need to use {{outlet}} for achieve this.
create diffrent outlets where you need to show diffrent templates by overriding application template
{{outlet}} //application hbs default one
{{outlet "view1"}} // another template
{{outlet "view2"}} //another template
there should be view1.hbs and view2.hbs in order to render those templates

Ember js get object from previous route

I am building my first EmberJS app.
Initially from index route, I will display an A. When user click A, it will route to /a. Component A will have a field url, after fill in and click a button, it will route to /b. Component B also has a field email. Fill in and click a button it will route to /summary which displays what I filled in A and B. How could I do it in best practice?
I am using ember-cli and this.transitionTo(/b) to go to route /b
It seems like nested routes would be good for this implementation.
/a - route
model(){
return {url:'default'};
}
a.hbs
{{comp-a model=model}}
/a/b - route
model(){
return {email:''};
}
a/b.hbs
{{comp-b model=model}}
/a/b/summary - route
model(){
return {amodel:this.modelFor('a'),bmodel:this.modelFor('b')};
}
a/b/summary.hbs
{{comp-a model=model.amodel }}
{{comp-b model=model.bmodel }}
Here is a tutorial that explains exactly how to make a multi-step form like you are asking for. http://romulomachado.github.io/2016/12/06/multi-step-form-with-ember.html
Using a nested route system, this is fairly straight forward.
Router.map(function() {
this.route('checkout', function() {
this.route('personal-info');
this.route('shipping-info');
this.route('payment-info');
this.route('confirmation');
});
});
and then you can use an 'order' or some 'form' model to keep the information alive.
I followed the example and built one out with the ability to edit and confirm at the end too. : )

How to add active class only for exact routes and not parent routes in ember js?

I have two routes which are nested like this.
router.js
this.route('profile', function() {
this.route('edit');
});
and couple of navbar links for these routes like this..
navbar.hbs
{{#link-to 'profile' tagName="li"}}<a href>View Profile</a>{{/link-to}}
{{#link-to 'profile.edit' tagName="li"}}<a href>Edit Profile</a>{{/link-to}}
The link-to helper adds active class to the li tag here. So when I am in profile route, the first link has active class and when I am in profile.edit route, both the links have active class. (apparently because both the routes get activated when profile.edit is visited.)
How can I avoid the parent route link to get the active class when in a child route?
Basically I don't want the first link (to profile) to have active class when in profile.edit route.
I figured it out if anyone else is facing same issue.
I just changed the link to profile and made it to explicitly profile.index.
navbar.hbs
{{#link-to 'profile.index' tagName="li"}}<a href>View Profile</a>{{/link-to}}
{{#link-to 'profile.edit' tagName="li"}}<a href>Edit Profile</a>{{/link-to}}
This way, When in profile.edit route, the first link does not get the active class.

Emberjs renders the wrong template in a nested route

I have a nested route that looks like this:
App.Router.map(function(){
this.resource('comment', {path: '/:commentId'}, function(){
this.route('edit');
});
});
In my markup, I have a {{#linkTo 'comment.edit' content}} which correctly transitions and updates the URL. However, the wrong template is displaying. Instead of getting the 'edit' template, it displays the 'index' template. This only seems to be occurring in the nested route of dynamic resources. All other nested routes render the correct template. Has anyone else run into this issue in Emberjs?
Here, I have attached a twiddle, which works fine for me.
https://ember-twiddle.com/a2f91851a451a5da953a