AngularJS : Developing your first application – Part 2

This post is a continuation and  is second part of my earlier blog post on developing your first angular application in AngularJS.In this post we will further develop on our weather application while exploring few more important concepts of angularJS.So lets get started …

You can refer to the code written so far at this location.

Modules

So far javascript code we have written is all at global level and there is no modularization.AngularJS has a concept of modules and any professional angularJS application will for sure use modules for organizing the application.

So what are modules ?

Modules are the logical entities where all your controllers ,directives ,services etc exist.Its a way of wiring up all you components under one entity.

You can consider it similar to Assemblies in .NET framework.They are reusable containers which can be referenced in other modules.Lets add module to our existing application .Code is given below.

<html>
<head>
<script data-require="angular.js@*" data-semver="1.2.21" src="https://code.angularjs.org/1.2.21/angular.js"></script>
 <link rel="stylesheet" href="style.css" />
 <script src="script.js"></script>
</head>
 <!-- Use the name of module to load-->
 <body ng-app="WeatherApp">
 <div ng-controller="WeatherController">
 <h1 ng-bind="title"></h1>
 <label for="Name">Name of the Place :</label>
 <input required="" name="Name" type="text" ng-model="place" />
 <input type="submit" ng-click="getWeatherData()" value="Get Weather Info" />
 <div><h3>{{info}}</h3></div>
 </div>
 </body>
</html>

 

//IIFE - Immediately invoked function expression

(function(){

//Define module

app= angular.module("WeatherApp",[]);

var WeatherController = function($scope) {
 $scope.title = "Weather Information";

 $scope.getWeatherData = function() {
 $scope.info = "Fetching weather information for "
 + $scope.place + "...";
 };

};

//Register controller with module

app.controller("WeatherController",WeatherController);

}());

Lets get into the details of the changes we did in the above code.

HTML:

Line 8 : Added value for ng-app  attribute viz. WeatherApp which will be the name of the module.Now when angular encounters ng-app directive it will look for WeatherApp module and load that.

JavasScript:

Line 7: Here we use angular.module  function to define new module called WeatherApp .Second parameter is an array of modules on which WeatherApp module has dependency .In our case it will be empty.

Line 21: Here we register our  controller’s constructor function with the module by using .controller  method.

Line 3: I skipped this line earlier to come back to it in the last.This is where we are defining a JavaScript IIFE (Immediately invoked function expression.pronounced as ‘iffy’).Our code can work without iffy as well but enclosing the code in iffy makes sure that we dont have name conflicts when we are using lot of third party libraries.So its just a best practice.

So this wires up our code with modules.

Services

Next lets look into the concept of angular services.

As per AngularJS documentation:

Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.

So services as name suggests are basically a common useful functionality which can be used across application.Few of the inbuilt services which angular provides include http calls ($http), routing ($route),window related ($window),url related ($location) etc.

Also Services are singleton objects which are used across application and they are lazily instantiated.

Using $http Service

In this section we will be using $http service to make http calls to an external API to get weather data. So below is the code.

<html>

<head>
 <script data-require="angular.js@*" data-semver="1.2.21" src="https://code.angularjs.org/1.2.21/angular.js"></script>
 <link rel="stylesheet" href="style.css" />
 <script src="script.js"></script>
</head>
<!-- Use the name of module to load-->
<body ng-app="WeatherApp">
 <div ng-controller="WeatherController">
 <div id="input">
 <h1 ng-bind="title"></h1>
 <label for="Name">Name of the Place :</label>
 <input required="" name="Name" type="text" ng-model="place" />
 <input type="submit" ng-click="getWeatherData()" value="Get Weather Info" />
 <div>
 <h3>{{info}}</h3>
 </div>
 </div>
 <!-- Binding to show weather data -->
 <div id="output">
 <h3>Name : {{weatherData.name}} </h3>
 <h3>Temperature : {{weatherData.main.temp}} Deg K</h3>
 <h3>Pressure : {{weatherData.main.pressure}} mBar</h3>
 <h3>Humidity : {{weatherData.main.humidity}} %</h3>
 </div>
 </div>
</body>

</html>

 

//IIFE - Immediately invoked function expression

(function(){

//Define module

app= angular.module("WeatherApp",[]);

var WeatherController = function($scope,$http) {

 $scope.title = "Weather Information";

 $scope.getWeatherData = function() {

 //Calling http service

 $http.get("http://api.openweathermap.org/data/2.5/weather?q=" + $scope.place)
 .then(onSuccess, onError);
 };
 //Success method

 var onSuccess = function(response) {
 $scope.message = "Weather Information for " + $scope.place;
 $scope.weatherData = response.data;
 };
 //Error method

 var onError = function(response) {
 $scope.info = "Could not retrieve data";
 };

};

//Register controller with module
app.controller("WeatherController",WeatherController);

}());

Lets get into the code.

JavaScript:

Line 9: First step in using http service is to add it as argument in the controller function where it will be injected automatically

Line 17: Here we are calling external service to get the weather data.Point to note here is that get  method is an asynchronous operation and does not return results immediately.What it returns is an object called Promise.You can attach callbacks to promises which will be called when the data is available and thats what we have done in our code.We have onSuccess  and onError   callbacks associated with this promise object.If you are familiar with C# language, concept of promise is similar to async / await  in C#.

Line 22 & 28: This is the implementation of callback functions.In onSuccess  function we are assigning the data received in the response object to our scope so that we can use it through databinding in our html code.

HTML:

Line 21 : Here we have added a div to show weather data where  h3 tags are bound with weatherData object from scope .

Below is the output of the code:

image

So we have our basic application ready.Further in this post I will talk about few more useful directives that are helpful in getting started with your first application.

ng-Show and ng-Include

Currently the initial screen our application doesn’t look very nice.

image

Although we have not searched for anything yet still the application shows me the empty labels for Name,Temperature etc.Ideally we would like our output section to be shown only when we have some data available.

To achieve this we can use ng-show  directive as shown below.

<!-- Binding to show weather data -->
 <div id="output" ng-show="weatherData">
 <h3>Name : {{weatherData.name}}</h3>
 <h3>Temperature : {{weatherData.main.temp}} Deg K</h3>
 <h3>Pressure : {{weatherData.main.pressure}} mBar</h3>
 <h3>Humidity : {{weatherData.main.humidity}} %</h3>
 </div>
 </div>

Giving “weatherData” as value for ng-show  makes sure that the div element is shown only when weatherData object has value.Similar to ng-show  we have ng-hide  as well (with opposite functionality obviously).

Further we can move this whole output section to a separate file and include it in the main file using ng-include directive as shown below.

  <div id=&quot;output&quot; ng-show=&quot;weatherData&quot; ng-include=&quot;'weatherinfo.html'&quot;>
 </div>

Note : Make sure you are giving file name in single quotes otherwise angular will look for a property with the same name in scope object.

ng-repeat

Lets suppose now we need to enhance our application and have to show ,along with current information, historical weather data for the whole day as well.

Below is the code for doing this.

//IIFE - Immediately invoked function expression
(function(){

//Define module
app= angular.module("WeatherApp",[]);

var WeatherController = function($scope,$http) {

 $scope.title = "Weather Information";

 $scope.getWeatherData = function() {

 //getting current weather information

 $http.get("http://api.openweathermap.org/data/2.5/weather?q=" + $scope.place)
 .then(onSuccess, onError);
 //getting historical weather information

 $http.get("http://api.openweathermap.org/data/2.5/history/city?type=day&amp;start=1356998400&amp;q="+ $scope.place)
 .then(onHistorySuccess,onHistoryError);
 };

 var onSuccess = function(response) {
 $scope.message = "Weather Information for " + $scope.place;
 $scope.weatherData = response.data;
 };

 var onError = function(response) {
 $scope.info = "Could not retrieve data";
 };

 var onHistorySuccess=function(response){
 $scope.historicalInfo = response.data.list;
 };

 var onHistoryError = function(response){
 $scope.info = "Could not retrieve historical data";
 };

};

//Register controller with module

app.controller("WeatherController",WeatherController);

}());

Weatherinfo.html

<div>
 <h3>Name : {{weatherData.name}}</h3>
 <h3>Temperature : {{weatherData.main.temp}} K</h3>
 <h3>Pressure : {{weatherData.main.pressure}} mBar</h3>
 <h3>Humidity : {{weatherData.main.humidity}} %</h3>
</div>
<div>
 <table ng-show="historicalInfo">
 <caption>
 <h3>Historical Data</h3>
 </caption>

 <tr>
 <th>Time</th>
 <th>Temperature (K)</th>
 <th>Pressure (mBar)</th>
 <th>Humidity (%)</th>
 </tr>
 <tr>
 </tr>
 <tr ng-repeat="info in historicalInfo">
 <td>{{info.dt*1000 | date:'yyyy-MM-dd HH:mm:ss'}}</td>
 <td>{{info.main.temp}}</td>
 <td>{{info.main.pressure}}</td>
 <td>{{info.main.humidity}}</td>
 </tr>
 </table>
</div>

CSS:

table, td, th {
    border: 1px solid gray;
}

th {
    background-color: gray;
    color: white;
}

Below is the explanation for the code we added:

JavaScript:

Line 19: Here we are making another call to a service to get historical data and are registering our callbacks with the promise.Nothing new here it is same as our earlier service call.

Line 32: In this code snippet we are getting the response data and assigning it back to historicalInfo property of scope object.Only difference this time is that historicalInfo is an array.

HTML:

Line 8: We are defining a table where the formatted historical data will be shown.

Line 21: Ok,now the most interesting point is the use of ng-repeat directive to repeat the table rows for the array data. This is equivalent of looping in programming languages and is similar to foreach  in C#.

CSS:

This is just basic CSS to format the HTML table.

Below is the final output of our application.

image

Well this is just the tip of the ice berg and there is much more powerful stuff to be explored in AngularJS.Hope these two posts will help you get started with AngularJS.

Click here to play with the current application and checkout the code.
To further review these concepts you can go to this excellent pluralsight course on getting started with Angular JS by Scott Allen.

 

Tagged on: , ,

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.