AngularJS with JSONP and how I get to work on time

Hallstein Brøtan

My every morning challenge is reaching the bus to get to work on time. And the bus schedule is not something to rely on.
Fortunately, the bus company in Oslo (called "Ruter" from now on) has its own REST API with real time data [1].

This is how I created my personal bus stop schedule with real time data.

Contents:

  1. What is JSONP
  2. Using JSONP with Angular
  3. Ruter REST API
  4. Date formatting with MomentJS
  5. The final code
  6. The final result

1. What is JSONP

Getting the data from the Ruter REST API was not straightforward.
Creating a simple $http.get() request resulted in the following error message :

XMLHttpRequest cannot load http://reis.trafikanten.no/reisrest/realtime/getrealtimedata/3010435.

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

Basically, the Ruter REST API doesn't accept my request. So how can I get around that?

Enter JSONP :

"JSONP or "JSON with padding" is a communication technique used in JavaScript programs running in web browsers to request data from a server in a different domain, something prohibited by typical web browsers because of the same origin policy." - Wikipedia [1].

2. Using JSONP with Angular

The AngularJS $http service has a built-in method called "jsonp".
Populating my $scope.realTimeData object is very simple:

    $scope.realTimeData;

    var url = "some REST API Url" + "?callback=JSON_CALLBACK";

    $http.jsonp(url)
        .success(function(data){
            $scope.realTimeData = data;
        });

Also, the url had to be appended with ?callback=JSON_CALLBACK.
Btw, you can read more about Angular basics in one of Yngve's blog posts: [3].

3. Ruter REST API

The Ruter REST API has a method for getting the id of the different bus stops. I retrieved the id of my bus stop, and got the URL for getting real time bus information for this stop. Of course, the Ruter REST API supports JSONP.

4. Date formatting with MomentJS

The Ruter REST API returns dates in JSON format /Date(1198908717056)/, so I used the awesome MomentJS [4] and created an Angular filter for date formatting :
The MomentJS function fromNow() gives me the remaining time until the given/input time.
If I wanted the date formatting in Norwegian, I could just uncomment moment.lang('nb').

.filter('fromNow', function() {
        return function(dateString) {
            //moment.lang('nb'); 
            return moment(dateString).fromNow();
        };
 }) 

5. The final code

myBusStop.html :

<!DOCTYPE html>
<html class="no-js" lang="en" ng-app="myBusStopApp">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My bus stop - Real time data</title> 
    <link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
    <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">   
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script>   
    <script src="http://momentjs.com/downloads/moment.min.js"></script>
    <script src="http://momentjs.com/downloads/moment-with-langs.min.js"></script>
    <script src="myBusStop.js"></script>
</head>
<body style="margin-top:2%;font-size:14px;font-family:Open Sans;padding-left:2%;padding-right:2%;">
<div ng-controller="myBusStopCtrl">
    <center>
    <div class="table-responsive" style="max-width:800px;">
    <table class="table table-striped" ng-show="realTimeData.length>0">
        <thead>
            <tr class="info">
            <th>Bus#</th>
            <th>Destination</th>
            <th>Wait time</th>          
            </tr>
        </thead>
        <tbody>
            <tr ng-repeat="item in realTimeData">
                <td>{{item.LineRef}}</td>
                <td>{{item.DestinationName}}</td>
                <td>{{item.ExpectedArrivalTime | fromNow }}</td>            
            </tr>
        </tbody>
    </table>
</div>
</center>
</div>
</body>
</html>

myBusStop.js :

angular.module('myBusStopApp', [])

.filter('fromNow', function() {
        return function(dateString) {
            //moment.lang('nb'); 
            return moment(dateString).fromNow();
        };
 })

.controller('myBusStopCtrl', ['$scope', '$http', function ($scope, $http) {
    $scope.realTimeData;

    var url = "http://reis.trafikanten.no/reisrest/realtime/getrealtimedata/3010435" + "?callback=JSON_CALLBACK";

    $http.jsonp(url)
        .success(function(data){
            $scope.realTimeData = data;
        });

}]);

6. The final result

The resulting web site will look like this (with basic Bootstrap CSS) :

FinalResult

Of course, I want this on my front door, so I always know if I have to run or not... (I know, I got mad Visio skills..)

BusOnDoor

[1] - http://labs.ruter.no/
[2] - http://en.wikipedia.org/wiki/JSONP
[3] - http://blog.novanet.no/angularjs-getting-started-with-the-basics-2/
[4] - http://momentjs.com/