Overview

Angular Solar Starter

NOTE: I decided that using controller as was too difficult when it came to testing. So for now, I have stripped it out of my own code and of this assignment. This means that if you created a version of this code that uses controller as, you will have to strip it out completely. That can be tricky, but I have done so in my code, and hopefully I have done so in the code now found in these instructions. The pith instruction: If you see mainController with a small em in your code, then remove it. For instance, mainController.index becomes index in your HTML and $scope.index in your MainController. If you want to keep the controller as syntax and feel you can get the tests to work while doing so, then do so. But at least for now, I do not recommend that for anyone in the class. It gets tricky when loading templates and we are not ready for that yet.

The goal of this assignment is to load a file called Renewable.json and iterate over its contents. This JSON file contains an array of objects. We will use a number control to iterate through the array and a directive to display the objects.

Our goal, at this stage, is to get a proof of concept app running. This will be the first of multiple iterations.

Angular Solar Starter

To ensure our code works, we will take the first steps toward writing tests with HTML fixtures loaded from disk.

To get rid of locale error in Cloud 9: LC_ALL=C

Step One

From the root of your repository, copy the AngularDirectiveTesting project to a new project call SolarExplorer. Then navigate to your new project folder:

cp -r Week04-AngularDirectiveTesting/ Week05-SolarExplorer
cd Week05-SolarExplorer

If necessary, install your packages: npm install && bower install.

In routes/index.js change the title to AngularSolarExplorer lastname, where lastname is your last name. Make similar changes in bin/www and package.json.

Run karma start to confirm all is working.

Step Two: Tests

In the files section of karma.conf.js make sure app.js is loaded first and that you are loading ng-route:

'public/components/jquery/dist/jquery.min.js',
'public/components/angular/angular.js',
'public/components/angular-mocks/angular-mocks.js',
'public/components/angular-route/angular-route.js', << == HERE
'node_modules/jasmine-jquery/lib/*.js',
'public/javascripts/app.js',      << ==== HERE
'public/javascripts/*.js',
// CODE OMITTED HERE

In test-basic, let’s start by declaring a variable and method that we will want to create. We will mark this as fit to see that we want to get those tests to pass first. Put them right after the beforeEach methods. Anticipating where we will be going, also modify the code that tests if we loaded a fixture:

it('should be possible to access the renewable fixture', function() {
    var spanElement = document.getElementById('renewable');
    expect(spanElement).toBeDefined();
    console.log(spanElement);
    expect(spanElement.innerHTML).toContain('First');
    expect(spanElement.innerHTML).toContain('Btu');
    expect(spanElement.innerHTML).toContain('quadrillion');
});

fit('should find the index', function() {
    expect( scope.index).toBe(0);
});

fit('should have a getRenewable method ', function() {
    expect(scope.getRenewable).toBeDefined();
});

it('should be possible to access the fixture', function() {
    var spanElement = document.getElementById('renewable');
    expect(spanElement).toBeDefined();
});

The first two tests may not pass yet, but they should by the time we done.

Step Three

Let’s build in Angular Routing right from the start by copying in the relevant files from AngularRoutes:

cp ../Week03-AngularRoutes/views/main.jade views/.
cp ../Week03-AngularRoutes/views/about.jade views/.
cp ../Week03-AngularRoutes/public/javascripts/about.js public/javascripts/.
cp ../Week03-AngularRoutes/public/javascripts/main.js public/javascripts/.
cp ../Week03-AngularRoutes/public/javascripts/app.js public/javascripts/.

In layout.jade, make sure you are loading:

  • angular-route.js
  • app.js
  • main.js
  • about.js

Use bower install to ensure that angular-route is available and that it is “saved” to bower.json.

NOTE: I’m intentionally being a little vague here. If you need a reminder on how to set up layout.jade or bower.json, see the Angular Routes assignment.

Stop loading control.js, but don’t delete it yet.

In index.jade, set up your menu as in AngularRoutes:

nav.navbar-inverse.navbar-fixed-top
  .container
    navbar-header
      ul.nav.nav-pills
        li(ng-class="{ active: isActive('/')}")
          a(ng-href='#/') Home
        li(ng-class="{ active: isActive('/about')}")
          a(ng-href='#/about') About

Beneath this, and at the same level as the nav, create a second container, as in Angular Routes. Include a DIV with data-ng-view in this second .container. For instance, the second container, the one not in the nav, might look like this:

.container
  h1= title
  p Welcome to #{title}

  div(data-ng-view="")

Step Four: Get the data

Create a folder called public/data. Download three files I created based on public data provided by the government. Put them in your data directory. The simplest way to get them is shown below. Just block copy the lines, navigate to the root of your project, and paste them in:

cd public
mkdir data
cd data
wget https://s3.amazonaws.com/bucket01.elvenware.com/downloads/Renewable.json
wget https://s3.amazonaws.com/bucket01.elvenware.com/downloads/EnergyTypes.json
wget https://s3.amazonaws.com/bucket01.elvenware.com/downloads/RenewableTypes.json

Alternatively, you can download them and save them to disk:

Step Five: Main Jade

Add a button and a number control to main.jade:

button.btn.btn-primary(ng-click="getRenewable()") Energy Renewable

div
    label
        | Number:
        input(type='number', name='input', ng-model='index', min='0', max='10', required='')

hr

When the button is clicked, a method on your controller called getRenwewable will be called. When the input control is incremented or decremented, a value on your controller called index is modified. In particular, index will contain the same value as the input control.

Step Six

Set up main.js and use dependency injection to pass in $http as the sole parameter to the anonymous callback for your MainController:

  elfApp.controller('MainController', function($scope, $http) {
     // CODE OMITTED HERE
  });

Inside the controller add a method to load your JSON and store it in a variable called renawable. In particular, we are, at this stage, loading only the Renewable.json file:

$scope.getRenewable = function() {
    console.log('getRenewable');
    $http.get('data/Renewable.json')
        .then(function(res){
            console.log(res.data[0]);
            $scope.renewable = res.data;
        });
}

We also add our index for tracking the data in the INPUT control:

$scope.mainData = "Main Data";
$scope.index = 0;

Step Seven: Directive

Create a directive and display all eight fields of the JSON:

elfApp.directive('elfRenewable', function() {
    'use strict';
    return {
        controller: 'MainController',
        template: 'First: &#123;&#123;renewable[index].Year&#125;&#125; ' +
        '<br>Solar: &#123;&#123;renewable[index]["Solar (quadrillion Btu)"]&#125;&#125;' +
        '<br>Geothermal: &#123;&#123;renewable[index]["Geothermal (quadrillion Btu)"]&#125;&#125;' +
        // CODE OMITTED HERE...
    };
});

Recall that in JavaScript the following are identical:

myObject.foo = 1;
myObject['foo'] = 1;

After you complete the template in the code above, you should convert the directive to work with a templateUrl rather than a template:

controller: 'MainController',
templateUrl: 'renewable'

This is probably the simplest path to being able to complete the tests, so it is a step most developers would take while ensuring their code is testable. Remember that you can use one of the html to jade utilities to help with the process.

Testing

Convert your “marie” tests to work with the renewable data and directive. These tests are already written, but they work with the marie directive. Change them so they work with the new renewable directive and renewable fixture. For instance, you will need to use our global jade npm package to convert your renewable.jade file to a renewable.html fixture and load it in your tests. The steps involved were all described in the previous assignment on Angular Directives.

For instance, this test passes for me:

it('tests scope variable access in template loaded through fixture', function() {
    // Get element from fixture
    scope.renewable = [{
        "Year": "2017",
        "Solar (quadrillion Btu)": "0.8045307",
        "Geothermal (quadrillion Btu)": "0.2349284",
        "Other biomass (quadrillion Btu)": "0.50916",
        "Wind power (quadrillion Btu)": "2.202328",
        "Liquid biofuels (quadrillion Btu)": "1.2329197",
        "Wood biomass (quadrillion Btu)": "1.9860924",
        "Hydropower (quadrillion Btu)": "2.5859957"
    }];

    var el = document.getElementById('renewable');

    // ETC. The rest of the code is nearly, but not exactly identical to the marie code.
});

We will see a better way to mock scope.renewable on Monday.

Turn it in

Push, and if necessary, specify the folder your work is in.

NOTE: No nested project folders!