Up until now, we have seen that when you visit a URL /example
, which maps to route app/routes/example.js
and app/routes/example/index.js
, this renders app/templates/example.hbs
and app/templates/example/index.hbs
templates. To change this behavior, Ember.js provides us with a hook that is used to resolve which templates to render for the current route.
One common use case for customizing which templates to render is when your application template has multiple outlets and you want to render a particular route on an outlet other than the default one.
Let's see this by an example. We will be using the bootstrap
library in our project. For this, we need to first install the bootstrap
dependency in our project by using the following:
bower install --save-dev bootstrap
So, in the chapter-4/example4
directory, we need to run the preceding command. This should fetch and install the bootstrap
library in the example4/bower-components/
directory. Now we need to tell our asset pipeline broccoli to include the bootstrap assets (css, js, fonts, images) in our vendor.js
and vendor.css
files. To do this, we will have to make changes in example4/app/Brocfile.js
, and we will have to add the following lines in the file:
app.import('bower_components/bootstrap/dist/css/bootstrap.css'), app.import('bower_components/bootstrap/dist/css/bootstrap.css.map', { destDir: 'assets' }); app.import('bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot', { destDir: 'fonts' }); app.import('bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf', { destDir: 'fonts' }); app.import('bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg', { destDir: 'fonts' }); app.import('bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff', { destDir: 'fonts' }); app.import('bower_components/bootstrap/dist/js/bootstrap.js'),
The bootstrap-specific files which we need to add to Brocfile.js
Now, we are good to go and we can now start using the bootstrap glyph icons, css, and js in our code.
We will consider a use case in which our application has a sidebar and a main body content. Both the sidebar and the main body should be customizable. This also means that our different routes can have different sidebars and body content.
The code for this example is present at https://github.com/suchitpuri/emberjs-essentials/tree/master/chapter-4/example4.
Since our application has a sidebar and a main body, let us first create the application template that accommodates these two components. Since these components are customizable, we will have to define two outlets to render route-specific content in these two components.
If you look at application.hbs
, present at example4/app/templates/application.hbs
, you will notice that we have defined two templates: one for the sidebar content and one for the body:
<ul class="sidebar-nav" id="sidebar"> {{outlet sidebar}} </ul> <div class="row"> <div class="col-md-12"> {{outlet}} </div> </div>
Code snippet from application.hbs is present at example4/app/templates/application.hbs
Now, we need to tell our routes to render different templates in different outlets. Ember.js provides us with a hook to override which template to render in different outlets.
The renderTemplate
method of Ember.Route
provides this hook. The default behavior of this hook is to render the matching template in the application
outlet of its parent route.
Now, as our requirement is different, we will have to override this method to provide our implementation of rendering the template matching this route.
Let's look at the index
route of our application, as follows:
import Ember from "ember"; export default Ember.Route.extend({ renderTemplate: function(){ this.render('sidebar',{ outlet: "sidebar" }); this.render('index') } });
The index route is present at example4/app/routes/index.js
In the preceding code, we use this.render
method to tell the router about the name and options of the template to render. The first argument is the name of the template to render. The options object can supply the following properties:
{ into: 'favoritePost',// the template to render into outlet: 'comment',// The name of the outlet in that template controller: 'blogPost'//The controller to use for that template }
The into
property specifies which template to render the current template in, the outlet
property specifies which outlet to use in the above template, and the controller
property specifies which controller to use when rendering the specified template.
As you can see from the above index route code, when anyone visits the /
URL, we inform the index
route to render the sidebar
template in the sidebar
outlet and the index
template in the default application
template.
Similarly, we can create other additional routes that render different templates inside their respective outlets. For example, in our example4
application, we define another route named as about
, which renders the about_sidebar
template in the sidebar
outlet, and the about
template in the default unnamed outlet present in the about
template.
import Ember from "ember"; export default Ember.Route.extend({ renderTemplate: function(){ this.render('about_sidebar',{ outlet: "sidebar" }); this.render('about') } });
The about route is present in example4/app/routes/about.js
When you run this application and open http://localhost:4200/
on your browser, you will see something like the following screenshot:
Now, when you navigate to the http://localhost:4200/about
, you will see that both the sidebar and the page content change, as shown in the following screenshot:
18.191.176.194