How I Found A Job With Node + Angular, Part 4: Strap The Boot

In the previous posts we learned some Node.JS (and express) basics, incorporated CouchDB as our database and used some Angular.JS code to present our list of jobs.

But the final result we got is not a pretty sight, and not very usable or friendly. Those who know me, agree that I’m not that strong in UI desigbootstrapn or implementation, so to make our application prettier and more usable, let’s use some framework for that. There are a lots of frameworks out there, but I had my eye on Bootstrap. Maybe it’s my strong mobile orientation, maybe the ease of use or maybe it’s just one of the frameworks I encountered first. In any case, I like the thinking of Bootstrap makers, I like that it is a remarkable responsive UI framework, and that it is fairly easy to us. So you can download Bootstrap from here, and lets make some changes to our application, using Bootstrap styles:

<html ng-app="geojob">
<head>
  <title>GeoJob Finder - Bootstrap GeoJob</title>
  <link rel="stylesheet" href="bootstrap-3.1.1-dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="bootstrap-3.1.1-dist/css/bootstrap-theme.min.css" />
  <link rel="stylesheet" href="css/geojob.css" />
</head>
<body>
  <section class="container"  ng-controller="JobsController">
    <div class="header"><h1>GeoJob Finder <small>Bootstrap GeoJob</small></h1></div>
    We have a total of: {{jobs.total_rows}} jobs
    <div class="list-group">
      <a href="#" class="list-group-item" ng-repeat="job in jobs.rows">{{job.key}}</a>
    </div>
  </section>
  <script type="text/javascript" src="js/angular.min.js"></script>
  <script type="text/javascript" src="js/geojob-app.js"></script>
</body>
</html>

In lines 4-5 we added the Bootstrap css files (which reside under the ‘bootstrap-2.1.1-dist‘ sub folder). We used them to style our header (line 10) and replace the ugly header lines with a styled list (lines 12-14). The result was not perfect since it was stretched from the edges of the screen, so we added a css file to our application, to constrain the display width with the “container” class (line 6):

.container {
    width: 940px;
}

Now we have an appealing list of companies (lines 12-14):geojob3

Now let’s add the company details:

<html ng-app="geojob">
<head>
  <title>GeoJob Finder - Bootstrap GeoJob</title>
  <link rel="stylesheet" href="bootstrap-3.1.1-dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="bootstrap-3.1.1-dist/css/bootstrap-theme.min.css" />
  <link rel="stylesheet" href="css/geojob.css" />
</head>
<body>
  <section class="container"  ng-controller="JobsController">
    <div class="header"><h1>GeoJob Finder <small>Bootstrap GeoJob</small></h1></div>
    <div class="well well-sm">We have a total of: {{jobs.total_rows}} jobs</div>
    <div class="list-group companylist">
      <a href="#" class="list-group-item" ng-repeat="job in jobs.rows">{{job.key}}</a>
    </div>
    <div class="panel panel-default companydetails">
      <div class="panel-body">
        Name: <span style="float: right">{{company.key}}</span><br>
        Sector: <span style="float: right">{{company.sector}}</span><br>
        Employees: <span style="float: right">{{company.employees}}</span><br>
        Area: <span style="float: right">{{company.area}}</span><br>
        Location Name: <span style="float: right">{{company.locationName}}</span><br>
        Location Area: <span style="float: right">{{company.locationArea}}</span><br>
      </div>
    </div>
  </section>
  <script type="text/javascript" src="js/angular.min.js"></script>
  <script type="text/javascript" src="js/geojob-app.js"></script>
</body>
</html>

geojob4

And we need to modify our controller (Angular) so that when you select a company from the list, it will display the details on the right panel (via the {{company.xxxx}} predicates). We also need to create the selection code when clicking a list item. In the previous post we left something annoying – the value array returned by CouchDB ‘view’ API. Let’s fix this by making it more intuitive to use the values (e.g. key-value!).

function(doc) {
  emit(doc.companyname, {"area": doc.area, "employees": doc.employees, "sector": doc.sector, "locationName": doc.locationname, "locationArea": doc.locationarea});
}

Map function: the changes are self explanatory: we return an object with all the doc fields mapped to the object keys.

...
   app.controller('JobsController', function($scope, $http) {
      $scope.hello = "Hello GeoJob";
      $scope.jobs = {};
      $scope.company = {};

      $http.get("/jobs").success(function(data) {
         $scope.jobs = data;
      }).error(function() {
         alert("Error");
      });

      $scope.setCompany = function(company) {
        $scope.company = company;
      };

      $scope.isSelected = function(company) {
        return $scope.company == company;
      };
   });
...

We changed the controller by adding a selection function (lines 13-15, setCompany). It gets the job from the angular repeater and uses it as argument to the selection function (and save it to the controller “company” variable). We also added isSelected function (lines 17-19) so we can use it to highlight the selected company in the list.

...
    <div class="list-group companylist">
      <a href="#" class="list-group-item" ng-class="{active : isSelected(job)}" ng-repeat="job in jobs.rows" ng-click="setCompany(job)">{{job.key}}</a>
    </div>
    <div class="panel panel-default companydetails">
      <div class="panel-body">
        Name: <span style="float: right">{{company.key}}</span><br>
        Sector: <span style="float: right">{{company.value.sector}}</span><br>
        Employees: <span style="float: right">{{company.value.employees}}</span><br>
        Area: <span style="float: right">{{company.value.area}}</span><br>
        Location Name: <span style="float: right">{{company.value.locationName}}</span><br>
        Location Area: <span style="float: right">{{company.value.locationArea}}</span><br>
      </div>
    </div>
...

We changed the company list row so that it will be highlighted if this row is selected (line 3) by using the “ng-class” directive. We also added a click handler (by using the “ng-click” directive).
Now we can see that selecting a company display the company details in the right pane, and also the company is selected in the company list.

geojob5

Ignore the weird characters that you see in the screen images, some of the text is in Hebrew (it is no secret that I live in Israel, and obviously look for a new job in Israel), and we’ll fix this in the next parts of the tutorial.
In the next post we will add some mapping functionality (why do you think we left this blank area in the middle of the screen?).

How I Found A Job With Node + Angular tutorial series:

Part 1: Let’s Do Some Node
Part 2: Let’s Level Some Jobs
Part 3: The Angular Angle
Part 4: Strap The Boot
Part 5: Mind The Map
Part 6: Going Production

Leave a Reply

Your email address will not be published. Required fields are marked *