RkBlog

Hardware, programming and astronomy tutorials and reviews.

Basics of Ember.js application development

Using npm dependencies, creating routes and templates with styles and components logic

After setting up the base of our ember application we can start doing something more with it. For my tutorials I've picked AdminLTE template to make a admin panel alike application.

Check out previous ember tutorials too:

AdminLTE is a free admin panel template. Doing it the old way we would download the package and use AdminLTE styles and code in our Django (or Ember) templates. In this case it can be done differently. AdminLTE is available as npm package (node package manager) and we can set it as a dependency of our application:

bower install admin-lte

At the time of writing this installed version 2.3.2 and that's what I've added to bower.json:

"admin-lte": "2.3.2"

In the AdminaLTE documentation we will find the class names for the HTML skeleton of header, sidebar and main content area. We can use them in application.hbs - main template file:

<div class="wrapper">
    <header class="main-header">header</header>
    <aside class="sidebar-wrapper">aside</aside>
    <section class="content-wrapper">{{outlet}}</section>
</div>

outlet is a placeholder for content inserted from child routes, something like a block tag in Django. In this case each page (route) will put its content in the AdminLTE content block.

But we are still missing styles to make it look correctly. As AdminLTE is a dependency installed by bower we have to specify which files from that package we want to include. We can do that by listing them in ember-cli-build.js:

  app.import('bower_components/admin-lte/bootstrap/css/bootstrap.css');
  app.import('bower_components/admin-lte/dist/css/AdminLTE.css');
  app.import('bower_components/admin-lte/dist/css/skins/_all-skins.css');
  app.import('bower_components/admin-lte/plugins/jQuery/jQuery-2.1.4.min.js');
  app.import('bower_components/admin-lte/bootstrap/js/bootstrap.min.js');
  app.import('bower_components/admin-lte/dist/js/app.min.js');

You can find those files under those paths. Those files are also used in the AdminLTE templates showcased in the documentation. For additional JS widgets you will have to add their JS and CSS files.

We have styles and now we can make it look better by adding some content to the main template (application.hbs):

<html>
<head>

</head>
<body class="skin-blue">
<div class="wrapper">
    <header class="main-header">
        <a href="/" class="logo">
          AdminLTE
        </a>
        <nav class="navbar navbar-static-top" role="navigation">
          <a role="button" data-toggle="offcanvas" class="sidebar-toggle" href="#">
            <span class="sr-only">Toggle navigation</span>
        </a>
        </nav>
    </header>
    <nav class="sidebar-wrapper">
        <div class="main-sidebar">
            <div class="sidebar">
                <ul class="sidebar-menu">
                    <li><a href="#"><span>Link</span></a></li>
                    <li><a href="#"><span>Link</span></a></li>
                    <li><a href="#"><span>Link</span></a></li>
                </ul>
            </div>
        </div>
    </nav>
    <section class="content-wrapper">
        {{outlet}}
    </section>
</div>
</body>
</html>
AdminLTE template in EmberJS application

Theme variant is picked by class assigned to body class. With some links and header the page looks like it should. Now we can add actual page to our application - a new route:

ember generate route boxes

This will create a new page under URL /boxes. We can link to in in the side panel using link-to tag:

<li>{{#link-to "boxes"}}<span>boxes demo</span>{{/link-to}}</li>

when generating route we also got boxes.hbs template in app/templates. Let say we want to display three boxes there. Lets start with bootstrap grid:

<div class="row">
  <div class="col-xs-6 col-md-4">
      box
  </div>
  <div class="col-xs-6 col-md-4">
      box
  </div>
  <div class="col-xs-6 col-md-4">
      box
  </div>
</div>

We could paste a box in every slot but that would be code duplication. To do this better we can create a component:

ember generate component statistics-box

There will be a template app/templates/components/statistics-box.hbs in which we can add box HTML code:

<div class="info-box">
  <span class="info-box-icon bg-aqua"><i class="ion ion-ios-gear-outline"></i></span>
  <div class="info-box-content">
    <span class="info-box-text">CPU Traffic</span>
    <span class="info-box-number">90<small>%</small></span>
  </div>
</div>

Now we can use it in our boxes.hbs route template:

<div class="row">
  <div class="col-xs-6 col-md-4">
      {{statistics-box}}
  </div>
  <div class="col-xs-6 col-md-4">
      {{statistics-box}}
  </div>
  <div class="col-xs-6 col-md-4">
      {{statistics-box}}
  </div>
</div>
AdminLTE boxes in EmberJS application

We now have three boxes but without icons. Those icons are provided by font-awesome and ionicons. As they are available via npm we can add them as dependencies, for example (bower.json):

"components-font-awesome": "4.4.0"

And install with bower install. After that we have to add required files to ember-cli-build.js:

  app.import('bower_components/components-font-awesome/css/font-awesome.min.css');
  app.import('bower_components/components-font-awesome/fonts/FontAwesome.otf', {
      destDir: 'fonts'
  });
  app.import('bower_components/components-font-awesome/fonts/fontawesome-webfont.eot', {
      destDir: 'fonts'
  });
  app.import('bower_components/components-font-awesome/fonts/fontawesome-webfont.svg', {
      destDir: 'fonts'
  });
  app.import('bower_components/components-font-awesome/fonts/fontawesome-webfont.ttf', {
      destDir: 'fonts'
  });
  app.import('bower_components/components-font-awesome/fonts/fontawesome-webfont.woff', {
      destDir: 'fonts'
  });
  app.import('bower_components/components-font-awesome/fonts/fontawesome-webfont.woff2', {
      destDir: 'fonts'
  });

Using destDir we can set the folder to which given file will be inserted when the application is build. CSS files expects font files in fonts folder so we specify it so that everything works.

We can do the same for ionicons:

"ionicons": "2.0.1"
app.import('bower_components/ionicons/css/ionicons.min.css');
  app.import('bower_components/ionicons/fonts/ionicons.eot', {
      destDir: 'fonts'
  });
  app.import('bower_components/ionicons/fonts/ionicons.svg', {
      destDir: 'fonts'
  });
  app.import('bower_components/ionicons/fonts/ionicons.ttf', {
      destDir: 'fonts'
  });
  app.import('bower_components/ionicons/fonts/ionicons.woff', {
      destDir: 'fonts'
  });

And now our boxes have icons visible (sometimes it's required to restart ember server):

Awesome and ionicons icons

We have working component styles. Now it's time to make it a real dynamic and reusable component. Component take data in under specified variables and do something with it, usually display in some way. Change the component template (statistics-box.hbs) to:

<div class="info-box">
  <span class="info-box-icon bg-{{color}}"><i class="{{icon}}"></i></span>
  <div class="info-box-content">
    <span class="info-box-text">{{name}}</span>
    <span class="info-box-number">{{yield}}</span>
  </div>
</div>

Aside of yield everything is a variable displaying data assigned to it. The yield tag inserts content from a block tag (if we use the component as a block):

<div class="row">
  <div class="col-xs-6 col-md-4">
      {{#statistics-box name="Foo Bar" color="aqua" icon="fa fa-github-alt"}}100%{{/statistics-box}}
  </div>
  <div class="col-xs-6 col-md-4">
      {{#statistics-box name="Rebels" color="yellow" icon="fa fa-rebel"}}1210{{/statistics-box}}
  </div>
  <div class="col-xs-6 col-md-4">
      {{#statistics-box name="Stormtroopers" color="green" icon="fa fa-empire"}}11{{/statistics-box}}
  </div>
</div>

Available icons are listed in the documentation. After making all those changes we get this:

Working components in ember application

In older ember versions view were responsible for this type of functionality. Now components replaced views and also controllers in many aspects.

Summary

In this tutorial I showed up how to use npm packages in ember.js application and how to create routes - pages as well as basic components that in future tutorials will hold most of the logic of our application.

What we will get in the end are models that will operate on Django Rest Framework API, routes of every subpage and many components responsible for doing something with models and their data.

RkBlog

10 January 2016;

Comment article