How I Found A Job With Node + Angular, Part 3: The Angular Angle

In the first post, I explained my frustration about seeking possible close (geographically) and awesome future employers. I started my journey towards geo aware job finding application by discussing Node.JS basics. In the previous post we added some database functionality with CouchDB.jquery

Now it is time to start showing some UI, to display the jobs stored in our database. There are many modern UI/Web frameworks that can do the job. My favorites are jQuery (mainly because of jQuery mobile anjquery-mobiled me being mobile oriented) and Angular.JS. I’ve chosen Angular for this tutorial. Download and install the Angular files. I would also recommend the excelleAngularJS-largent Angular free tutorial to get you started with basic Angular concepts.

Let’s create our first application files. We start with the html:

<html ng-app="geojob">
<head>
  <title>GeoJob Finder - Hello GeoJob</title>
</head>
<body>
  <div ng-controller="JobsController">
    <h1>GeoJob Finder - Hello GeoJob</h1>
    {{hello}}
  </div>
  <script type="text/javascript" src="js/angular.min.js"></script>
  <script type="text/javascript" src="js/geojob-app.js"></script>
</body>
</html>

You can see the important Anguler bits here:
line 1 – ng-app=”geojob” is the name of the application module.
line 6 – ng-controller=”JobsController” is our basic controller which will provide the data to be displayed in line 8, replacing the {{hello}} placeholder with the controller hello variable content. Also note that angular JavaScript and our application are placed in the “JS” sub folder.

And add the application:

(function() {

   var app = angular.module('geojob', []);

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

})();

Here we can see we named the application module “geojob” and created a simple “JobsControlloer” controller that has a single hello variable initialized to some predefined hello world message. And if we load geojob.html, we get:geojob1

Cool! Now we are ready to serve this page from our node server. Let’s define a simple node application that will do that:

var express = require('express');
var app = express();
app.use(express.static(__dirname + '/'));
app.get('/', function(req, res){
  res.sendfile('./geojob.html');
});
var server = app.listen(80, function() {
    console.log('Listening on port %d', server.address().port);
});

Lines 4,5 will serve our geojob.html file. However, since the html include some assets (Java scripts, and maybe css and images in the future) we define in line 3 that all static content should be served from the “/” path (you can change this to ‘/html/’ or whatever suits you, but keep in mind that the relative folder structure – /js etc. should be maintained). Run “node server.js” and point your browser to “http://localhost” and you should see the page above!

Now it’s time to use our database and use Angular to render the jobs that the server will return. We can use Angular “$http” service to perform the jobs query. Let’s modify our app:

(function() {

   var app = angular.module('geojob', []);

   app.controller('JobsController', function($scope, $http) {
      $scope.hello = "Hello GeoJob";
      $scope.jobs = {};
      $http.get("/jobs").success(function(data) {
         $scope.jobs = data;
      }).error(function() {
         alert("Error");
      });
   });

})();

As you can see we initialize a variable for the jobs (line 7), and retrieve it with the $http service (lines 8-12). Refreshing the browser (“http://localhost”) will pop the “Error” alert, obviously. We need to modify our server as well:

var express = require('express');
var nano = require('nano')('http://localhost:5984');
var geojob = nano.use('geojob');
var app = express();
app.use(express.static(__dirname + '/'));
app.get('/', function(req, res){
  res.sendfile('./geojob.html');
});
app.get('/jobs', function(req, res){
  geojob.view('jobs', 'jobs', function(err, body) {
    if (!err) {
      res.json(body);
    }
  });
});
var server = app.listen(80, function() {
    console.log('Listening on port %d', server.address().port);
});

Nothing new here. We are using nano for the database access, as in the previous post. We added a server route for “/jobs” (lines 9-15) so when the Angular controller will run the initialization code and perform the ajax http request (using the $http service), the server will query all the jobs in the database and return them in the response. Now if we refresh the browser, the pesky “Error” alert will not show up.

Line 10 require some explanation. We are usin nano (and CouchDB) view to retrieve the jobs information from the database.Explaining CouchDB views is beyonf the scope of this tutorial as it requires some Map/Reduce background, but fortunataly, we can simply create the view design (which includes a mapping function and a reducing function) in the futon console. For the jobs description in this post I choose to call both the design and the view “jobs”:

couch-job-view

As you can see the view design map function simply returns the company name as a key and the area and number of employees as the values (and we left the reduce section empty):

function(doc) {
  emit(doc.companyname, [doc.area, doc.employees]);
}

You can define the views in futon by selecting “temporary view…” and defining your design and view name after pressing “save as” to save your view:

temporary-view

You can also add view to the database programmatically with nano:

...
geojob.insert(
  { "views":
    { "jobs":
      { "map": function(doc) { emit(doc.companyname, [doc.area, doc.employees]); } }
    }
  }, '_design/jobs', function (error, response) {
    console.log("yay");
  });

So it’s time for some Angular magic – lets display the jobs:

<html ng-app="geojob">
<head>
  <title>GeoJob Finder - Hello GeoJob</title>
</head>
<body>
  <div ng-controller="JobsController">
    <h1>GeoJob Finder - Hello GeoJob</h1>
    We have a total of: {{jobs.total_rows}} jobs
    <div ng-repeat="job in jobs.rows">
    	<h1>{{job.key}}</h1>
    	Location: {{job.value[0]}}
    	Employees: {{job.value[1]}}
    </div>
  </div>
  <script type="text/javascript" src="js/angular.min.js"></script>
  <script type="text/javascript" src="js/geojob-app.js"></script>
</body>
</html>

And when we refresh our browser we get:geojob2

We changed the header to print the number of jobs that were returned from the “/jobs” request – jobs.total_rows, and used angular ng-repeat (lines 9-13) to repeat for each job and print the company name, area and number of employees.

Now we have the core functionality of retrieving and displaying our jobs (to add additional fields to the screen, simply modify the CouchDB view and add additional doc.XXXXX fields to the value array).
In the next post we will ditch this ugly UI presentation for something far more appealing.

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 *