Meeting Shwan : Great experience

Yesterday, I met one of the great of our industry Shawn Wildermuth and his wife Resa over the lunch in Delhi. For me it was memorable afternoon.

photo1

We talked lot and lot. Shwan was very down to earth and Resa was awesomely friendly. For me it was motivational meeting. Below I am listing 10 important points from the Shwan.

  • Learn while building
  • Key is to Fail
  • Be curious to learn new things
  • Rather than trying to motivate yourself , make yourself curious about the things
  • No harm in saying – I DON’T KNOW
  • If you think, you know EVERYTHING then rethink
  • Failure is good
  • Learn to say NO to few work even if there is good money in that
  • When you build, you understand
  • Only learning is not enough unless you don’t build.

I am very motivated after meeting Shwan. Looking forward to see him again  :)

AngularJS Custom Directive course by Dan Wahlin : Get discount here

I can give free access of the course to four of you. Tweet me with the course URL why you deserve free access of the course.

Click on this to get access of the course in 15$ only

clip_image002

I am learning AngularJS. And as always best to learn from the course of Dan Wahlin . He recently launched custom directive course Building AngularJS Custom Directives with Dan Wahlin on Udemy

Personally I find it one of the best course to master custom directives. Roughly course contents are listed below,

Section 1: Getting started with Directives

  • Introduction
  • The role of directives
  • Creating a hello word directives
  • Directive categories
  • Directive building blocks

Section 2: Shared and Isolated Scope

  • Introduction
  • Understanding Shared and Isolated Scope
  • Shared and Isolate Scope demo
  • @local scope property
  • = local scope property
  • = local scope property demo
  • &local scope property demo

Section 3: The link() function

  • The link() function
  • Building a table helper directive
  • Requiring ng-model
  • Using $parse() and eval()
  • Building a Google map directive
  • Using $scomplie and #interpolate service

Section 4: Using Controller in Directive

  • Using controller in directive
  • Replace link with directive
  • Adding controller
  • Understanding Transclusion

Section 5: Custom Directive in action

  • Building custom validator directive
  • Using $asyncValidators
  • Building Ajax overlay directive

You can find the course here: Building AngularJS Custom Directives with Dan Wahlin on Udemy.

Click on this to get access of the course in 15$ only

I can give free access of the course to four of you. Tweet me with the course URL why you deserve free access of the course.

Directives in AngularJS simplified with examples: Part 1

Thanks First

At the very beginning of this post, I want to give credit to following two online courses. What I learnt from these courses, converted in this post.

· AngularJS Custom directive course by Dan Wahlin.[Note: Click on this link to get 15% discount]

· AngularJS Directives Fundamentals by Joseph Eames on Plural Sight

 What is a Directive?

In the angularJS directives perform the following tasks,

  • It attaches specified behavior to DOM elements
  • It creates new element on the DOM
  • It transform the DOM elements.

In simple words, using directives we can modify the behavior of a particular DOM element or add new custom element on the DOM. For example ng-show is a directive. It modifies behavior of an element that whether that element will be visible or not.

Let us consider following code listing as an example,


<div ng-show="true">
    Hi I will be visible
</div>
<div ng-show="false">
    Hi I will not be visible
</div>

We are using built in directive ng-show to amend the behavior of the div. First div will be visible whereas second div won’t.

First custom directive

A very simple custom directive can be created as shown in below listing,


myApp.directive('myFirstDirective', function () {
    return {
        template: "<b>Hello from custom directive</b>",
        restrict: "E"
    }
})

Above is the minimal directive we can create. Custom directive can be created by using the directive method. It takes directive name and the function as the input parameters. There are some important points, you must keep in mind while creating a directive,

  • Directive name is provided in the camel case
  • On the view directive can be used by separating the camel case name of the directive either using dash, colon, or underscore
  • Combination of dash, underscore or colon can also be used

We have given the directive name as myFirstDirective. On the view it can be used either as my-first-directive or my:first:directive or my_first_directive or even as my_first-directive or my-first:directive

On the view custom directive myFirstDirective can be used as shown in below listing. As you see we are using the custom directive with various combinations of dash, underscore, and colon. For angular all three options are exactly the same.

<body>
    <my-first-directive></my-first-directive>
    <br />
    <my:first:directive></my:first:directive>
    <br />
    <my_first_directive></my_first_directive>
    <br />
    <my:first_directive></my:first_directive>
    <br />
    <my-first-directive />
</body>

In the chrome browser developer tools on selecting inspect element option, you can see that the directive template has been replaced with the html.

image

Custom directive can be used on the view in four different ways.

  1. As an attribute – set restrict value to A
  2. As a custom element – set restrict value to E
  3. As a comment – set restrict value to M
  4. As a class- set restrict value to C

Out of these four methods, as an attribute and as an element are widely used. In older version of some browsers comment and class ways of using directive can be used.

Custom Directive with data binding

Let us proceed to create a custom directive which will use the angularjs bindings. We have a controller as listed below,


myApp.controller('studentscontroller', ['$scope', function ($scope) {
    $scope.student = {
        name: "dj",
        age: 32,
        subject: [
            "math",
            "geography"
        ]
    }
}]);

Usually to display data from the controller, we use binding expression on the view. Other way to display data using the custom directive which will use the data binding. We can create custom directive with the binding expression as shown in listing below:

myApp.directive('studentDetail', function () {
    return {
        template: "<b>hey {{student.name}} is {{student.age}} old </b>",
        restrict: "E"
    }
});

As you notice inside the custom directive studentDetail, we are using the binding expression. Now we can use studentDetail custom directive on the view as shown in below listing,

<div ng-controller="studentscontroller">
    <student-detail></student-detail>
</div>

On the view you will get data renderd using the custom directive as shown in image below,

image

And on the element inspection in the chrome browser developer tool, you will find element in the DOM as shown in image below,

image

In the DOM if we want to replace the custom element that can be done by setting the replace option in the custom directive. Let us modify the studentDetail directive by setting the replace attribute to true.

myApp.directive('studentDetail', function () {
    return {
        template: "<b>hey {{student.name}} is {{student.age}} old </b>",
        restrict: "E",
        replace: true
    }
});

Now in the DOM, we will notice that custom element has been removed as shown in the image below,

image

Using templateUrl

When we create complex custom directive, template as a string could be tough to handle. We can have template in external HTML file and can be loaded using the templateUrl attribute. We can move the template in the external HTML file which must have the same name as of the directive. So let us add studentDetail.html file in the application and move template string the HTML file.

studentDetail.html

<div>
    <b>hey {{student.name}} is {{student.age}} old </b>
</div>

We need to modify the directive as shown in the listing below:

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetaildj.html",
        restrict: "E",
        replace: true
    }
});

Let us go bit creative and use bootstrap to make the template more immersive. I am using the bootstrap panel. Using the ng-show directive, we are hiding/showing the subject div.

<div class="panel panel-primary">
    <div class="panel-heading">
        {{student.name}} {{student.age}}
    </div>
    <div ng-show='!!student.subject'>
        Subjects:
        <ul ng-repeat="s in student.subject">
            <li>{{s}}</li>
        </ul>
    </div>
</div>

Events in the directive

Let us see that how can we work with events in directive. Let us say that we have an event in the controller as shown in below listing,

myApp.controller('studentscontroller', ['$scope', function ($scope) {
    $scope.student = {
        name: "dj",
        age: 32,
        subject: [
            "math",
            "geography"
        ]
    }

    $scope.setGrade = function (student) {
        student.grade = "A+"
    }

}]);

We have added setGrade function in the controller. We can use this event directly in the directive template as listed below,

<div class="panel panel-primary">
    <div class="panel-heading">
        {{student.name}} {{student.age}}
    </div>
    <div ng-show='!!student.subject'>
        Subjects:
        <ul ng-repeat="s in student.subject">
            <li>{{s}}</li>
        </ul>
    </div>
    <div ng-show='!!student.grade'>
        {{student.grade}}
    </div>
    <div ng-show='!student.grade'>
        <button class="btn btn-success" ng-click="setGrade(student)">set grade</button>
    </div>
</div>

In the directive template we added a button and using the ng-click directive handling the event on the button. In browser application will look like as shown in image next,

image

The problem with above approach is that the click event reside in the parent controller than being part of the directive. Hence it violates the rule of encapsulation. In idea scenario we will like to have click event function as the part of the directive.

AngularJS directive supports a controller inside that. We can add a controller inside the directive as shown in listing below,

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetail.html",
        restrict: "E",
        replace: true,
        controller: function ($scope) {
            $scope.setGrade = function (student) {
                student.grade = "B+"
            }
        }

    }
});

In the browser application will render exactly the same as it was running when the setGrade function was part of the controller.

Scopes in directives

AngularJS directives are of three types as mentioned below,

  1. Shared scope
  2. Inherited scope
  3. Isolated scope
Shared scope

Default scope is the shared scope. So far we have been working with the shared scope. In the shared scope, the directive share the scope of the controller, in which it is enclosed it.

Let us again consider the example used previously, studentDetail directive is enclosed inside the studentsController. By default studentDetail directive have the same scope as of the studentsController.

To understand it better try logging value of the $scope in the console for both the controller and the directive as shown in the listing below,

myApp.controller('studentscontroller', ['$scope', function ($scope) {
    $scope.student = {
        name: "dj",
        age: 32,
        subject: [
            "math",
            "geography"
        ]
    }
    console.log($scope);
}
]);

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetail.html",
        restrict: "E",
        replace: true,
        controller: function ($scope) {
            $scope.setGrade = function (student) {
                student.grade = "B+"
            }
            console.log($scope);
        }

    }
});

In the Google chrome developer tool you will find that id of both the $scope are the same.

image

In the shared scope the directive shared the scope of the controller it is enclosed in. Shared scope can be depicted by the next image. As you see that $scope object is being shared in between the controller and the directive. If in the directive we change data on the $scope object, it would be reflected to the controller.

image

In shared scope data attached to the $scope can be changed in the directive and it would be visible in the controller.

Inherited scope

Other option is directive can inherit the scope of the controller it is enclosed in. In this case scope of the controller will be visible to the directive whereas directive scope won’t be visible to the controller. The controller scope becomes the parent of the directive scope. Inherited scope can be set by setting the value of scope property to true as shown in next code listing.

myApp.controller('studentscontroller', ['$scope', function ($scope) {
    $scope.student = {
        name: "dj",
        age: 32,
        subject: [
            "math",
            "geography"
        ]
    }
    console.log($scope);
}
]);

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetail.html",
        restrict: "E",
        replace: true,
        scope: true,
        controller: function ($scope) {
            $scope.setGrade = function (student) {
                student.grade = "B+"
            }
            console.log($scope);
        }

    }
});

In the Google chrome developer tool we will find that id of directive $scope and the controller $scope are different.

image

However if we examine parent of the directive child scope, we will find that if of the parent is set to the id of the controller scope.

image

Isolated scope

Isolated scope is the most used scope in the angularJS custom directive. It allows us to work different data from the different instance of the same custom directive. Let us consider the studentDetail directive, and use it multiple times as shown in listing below,

<div class="container" ng-controller="studentscontroller">
    <student-detail>  </student-detail>
    <student-detail>  </student-detail>
    <student-detail>  </student-detail>
</div>

In the browser application will be rendered as shown in the next image. No point to guess that all four entry of directives are using the same data from the controller.

image

When you click on one of the set grade, it will set grade for all the four students as shown in the next image,

image

For sure we may not want this kind of behavior in the application. This problem can be solved with the isolated scope. To create directive with the isolated scope, set scope property to object while creating the directive. It is shown in the listing below,

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetail.html",
        restrict: "E",
        replace: true,
        scope: {},
        controller: function ($scope) {
            $scope.setGrade = function (student) {
                student.grade = "B+"
            }
            console.log($scope);
        }

    }
});

We have created isolated scope for the directive. Now scope is not shared in between the directive and the controller. At this point, on running the application we will find that data is not displayed in the application because scope is not shared.

When you click on one of the set grade, it will set grade for all the four students as shown in the next image,

By diagram let us try to understand shared and isolated scope.

image

 

By diagram let us try to understand shared and isolated scope.

image

image

Now the question bin front of us is that, in isolated scope how to share the data from the controller to the directive? In Isolated scope data can be shared using the local scope property. Directive with the isolated scope can talk to the outside world using the local scope properties. There are three options in local scope properties.

image

@local scope property

The @local scope property can access the string from the outside the directive. Using the @local scope property string value can be passed to the directive.

Let us assume we have a simple directive as shown in the listing below,

myApp.directive('aStudentDirective', function () {
    return {
        scope: {
            name: '@'
        },
        template: "Hi <b>{{name}}</b>",
        restrict: "E"
    }
})

In the above directive we are using the @ local scope property to read the string from outside the directive. Directive is used as shown in the listing below,

<div class="container" ng-controller="studentscontroller">
    <a-student-directive name="{{student.name}}"></a-student-directive>
</div>

In the directive student.name from the studentscontroller can be used. We are passing data to the directive as the string.

If you want local scope property name in the directive to be different than the property name that can be done as shown in the listing below,

myApp.directive('aStudentDirective', function () {
    return {
        scope: {
            name: '@studentname'
        },
        template: "Hi <b>{{name}}</b>",
        restrict: "E"
    }
})

Directive can be used as shown in the listing below,

 

<div class="container" ng-controller="studentscontroller">
    <a-student-directive studentname="{{student.name}}"></a-student-directive>
</div>

If we change value of student name in the controller, directive will be updated. However any change in the directive local property will not make any change in the controller.

=local scope property

Character = local scope property is used to pass object to the directive from the outside world. It also supports two way binding.

To understand it let us go ahead and recreate the controller as shown in the listing below,

myApp.controller('studentscontroller', ['$scope', function ($scope) {
    $scope.student1 = {
        name: "dj",
        age: 32,
        guardian: {
            mother: "abc",
            father: "xyz"
        },
        subject: [
            "math",
            "geography"
        ]
    }
    $scope.student2 = {
        name: "foo",
        age: 14,
        guardian: {
            mother: "pqw",
            father: "rty"
        },
        subject: [
            "physics",
            "geography"
        ]
    }
    $scope.student3 = {
        name: "loo",
        age: 21,
        guardian: {
            mother: "mnq",
            father: "wsy"
        },
        subject: [
            "math",
            "bilogy"
        ]
    }
}
]);

We have added more students to the $scope. This is pretty straight forward controller. We are going to use this controller to understand the local scope property =.

Next let us create a directive,

  • Using the isolated scope
  • Using the = local scope property to pass object to the directive from the outside world

Directive can be created as shown in the listing below,

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetail.html",
        restrict: "E",
        replace: true,
        scope: {
            student: '='
        },
        controller: function ($scope) {
            $scope.setGrade = function (student) {
                student.grade = "B+"
            }
        }

    }
});

On the HTML we can use the directive passing different value for the student as shown in listing below,

<div class="container" ng-controller="studentscontroller">
    <student-detail student="student1"></student-detail>
    <student-detail student="student2"></student-detail>
    <student-detail student="student3"></student-detail>
</div>

I have also modified the template in studentDetail.html as shown in below listing.

<div class="panel panel-primary">
    <div class="panel-heading">
        <h2>{{student.name}} {{student.age}}</h2>
    </div>
    <div class="panel-body">
    <div ng-show='!!student.subject'>
        Subjects:
        <ul ng-repeat="s in student.subject">
            <li>{{s}}</li>
        </ul>
    </div>
    <div class="well">
        Guardians:<br />
        Father : {{student.guardian.father}}<br />
        Mother : {{student.guardian.mother}}<br />
    </div>
    <div ng-show='!!student.grade'>
        {{student.grade}}
    </div>
    <div ng-show='!student.grade'>
        <button class="btn btn-success" ng-click="setGrade(student)">set grade</button>
    </div>
</div>
</div>

On running the application in the browser, we will find that data of three different students have been rendered. Now when you set grade of one student, another students will not get impacted.

image

Inherited scope example

Now to understand the inherited scope in the better way, let us say we have a requirement to collapse and expand the each student panel when user will click on the panel header. To do this,

  • Add ng-click directive on the panel header. When user click on the header function will be called in the directive controller.
  • Add ng-hide directive to the panel body. On clicking of the panel header panel body will be either collapsed or expanded.

Let us start with adding the ng-click and the ng-hide directive.


<div class="panel panel-primary">
    <div class="panel-heading" ng-click="hide()">

        <h2>{{student.name}} {{student.age}}</h2>
    </div>
    <div class="panel-body" ng-hide="isHidden">
        <div ng-show='!!student.subject'>
            Subjects:
            <ul ng-repeat="s in student.subject">
                <li>{{s}}</li>
            </ul>
        </div>
        <div class="well">
            Guardians:<br />
            Father : {{student.guardian.father}}<br />
            Mother : {{student.guardian.mother}}<br />
        </div>
        <div ng-show='!!student.grade'>
            {{student.grade}}
        </div>
        <div ng-show='!student.grade'>
            <button class="btn btn-success" ng-click="setGrade(student)">set grade</button>
        </div>
    </div>
</div>

In the above code listing, we have added ng-click directive (see panel-header div). On click event hide() function in the directive controller will be called. We also added ng-hide directive (see panel-body div)

Next in the directive we need to add hide() function and isHidden data to the $scope object of the controller which is the part of the directive.

myApp.directive('studentDetail', function () {
    return {
        templateUrl: "studentDetail.html",
        restrict: "E",
        replace: true,
        scope: {
            student: '='
        },
        controller: function ($scope) {
            $scope.isHidden = false;
            $scope.setGrade = function (student) {
                student.grade = "B+"
            }
            $scope.hide = function () {
                $scope.isHidden = !$scope.isHidden;
            }
        }

    }
});

On running the application in the browser, we will find that data of three different students have been rendered and we can expand and collapse student panel as shown in image below:

image

Parent and child directives

We notice that studentDetail directive is getting large. As application grows, it will be tough to manage a too big directive. Let us go ahead and take the guardian data and move it to a separate directive called studentGuardian.

We have created template as shown in the listing below:

studentGuardian.html

 


<div class="well">
    Guardians:<br />
    Father : {{student.guardian.father}}<br />
    Mother : {{student.guardian.mother}}<br />
</div>

Let us go ahead and create directive with the shared scope as shown in the listing below:

myApp.directive('studentGuardian', function () {
    return {
        templateUrl: "studentGuardian.html",
        restrict: "E"
    }
})

In the studentDetail directive, we can use the studentGuardian directive as shown in listing below,

<div class="panel panel-primary">
    <div class="panel-heading" ng-click="hide()">

        <h2>{{student.name}} {{student.age}}</h2>
    </div>
    <div class="panel-body" ng-hide="isHidden">
        <div ng-show='!!student.subject'>
            Subjects:
            <ul ng-repeat="s in student.subject">
                <li>{{s}}</li>
            </ul>
        </div>
        <student_guardian></student_guardian>
        <div ng-show='!!student.grade'>
            {{student.grade}}
        </div>
        <div ng-show='!student.grade'>
            <button class="btn btn-success" ng-click="setGrade(student)">set grade</button>
        </div>
    </div>
</div>

Now we have a nested directive studentGuardian inside the main directive studentDetail. And the studentGuardain directive working with the shared scope. We got a similar kind of requirement to expand and collapse the guardian section.

Let us start with adding ng-click and ng-show to the studentGuardian directive template. Now we have two div on the studentGuardian directive template. One will be displayed when in the expanded and other in the collapsed mode.

<div class="well" ng-show='isHidden' ng-click="showGuardian()">
    Guardians::::::
</div>
<div class="well" ng-show='!isHidden' ng-click="hideGuardian()">
    Guardians:<br />
    Father : {{student.guardian.father}}<br />
    Mother : {{student.guardian.mother}}<br />
</div>

Next in the studentGuardian directive,

  • Add a controller
  • Add isHidden data to the $scope of the studentGauradian template. We have isHidden data in the $scope of the studentDetail directive also. On purpose we are giving name same name to see the behavior of inherited scope
  • Added two functions hideGuardain and showGuardain to set the vale if isHidden false and true respectively
  • Value of scope property is set to true.

Modified directive is listed next,

myApp.directive('studentGuardian', function () {
    return {
        templateUrl: "studentGuardian.html",
        restrict: "E",
        scope: true,
        controller: function ($scope) {
            $scope.isHidden = false;
            $scope.hideGuardian = function () {
                $scope.isHidden = true;
                console.log('h' + $scope.isHidden);
            };
            $scope.showGuardian = function () {
                $scope.isHidden = false;
                console.log('s ' + $scope.isHidden);
            }

        }
    }
});

On running the application in the browser, we will find that now guardian can be expanded and collapsed separately. If we change the value of scope to false then when we click n guardian the whole panel will be collapsed/expanded since the isHidden variable is shared in the shared scope.

Summary

In this post we learnt about directive, custom directive, and scopes in the anularJS. In next post we will focus on decorator directives, link function etc. I hope you find this post useful. Thanks for reading.

Services in AngularJS simplified with examples

Read: 21 points cheat sheet on AngularJS controller and the $scope object

What is service?

  • It provides us method to keep data across the lifetime of the angular app
  • It provides us method to communicate data across the controllers in a consistent way
  • This is a singleton object and it gets instantiated only once per application
  • It is used to organize and share data and functions across the application

Two main execution characteristics of angular services are that they are singleton and lazy instantiated. Angular only creates instance of a service when an application component depends on it. On the other hand each application component dependent on the service work with the single instance of the service created by the angular.

image

Keep in mind that services are singleton object and gets instantiated once per angular app using the $injector and they gets created when angular app components need them.

Let us start with creating a very simple service. This service will find square of a given number. It is a good idea to put all the service in a separate JavaScript file. We have created service.js file and inside that creating a service or registering a service using the service method as shown below,

var CalculatorService = angular.module('CalculatorService', [])
.service('Calculator', function () {
    this.square = function (a) { return a*a};

});

An AngularJS service can be created or registered or created in four different ways,

  1. Using the service() method
  2. Using the factory() method
  3. Using the provider() method
  4. Using the value() method
  5. Using the constant() method

Further in the post we will talk about other options to create the service. Above we have created the calculator service using the service() method.

To use the service in the controller, we are passing the service module CalculatorService as dependency in the application module. Next in the controller we are passing name of the service Calculator to be used.

var myApp = angular.module('myApp', ['CalculatorService']);
myApp.controller('CalculatorController', function ($scope, Calculator) {

    $scope.findSquare = function () {
        $scope.answer = Calculator.square($scope.number);
    }
});

On the view we are using the controller to do the data binding as shown below,

<div class="container">
        <div>
            <div ng-controller="CalculatorController">
                Enter a number:
                <input type="number" ng-model="number">
                <button class="btn btn-danger" ng-click="findSquare()">Square</button>
                <div>{{answer}}</div>
            </div>
        </div>
    </div>

An angular application will render as shown below,

image

We can create a service using the factory as shown below. We are creating the service to reverse the string.

CalculatorService.factory('StringManipulation', function () {

   var r=  function reverse(s) {
        var o = '';
        for (var i = s.length - 1; i >= 0; i--)
            o += s[i];
        return o;
    }

   return{
       reverseString: function reverseString(name)
       {
           return r(name);
       }
   }

});

In the controller the StringManipulationService can be used as shown below:


myApp.controller('CalculatorController', function ($scope, Calculator) {

    $scope.findSquare = function () {
        $scope.answer = Calculator.square($scope.number);
    }
});

On the view we are using the controller to do the data binding as shown below,

<div ng-controller="StringController">
                Enter Name:
                <input ng-model="name">
                <button class="btn btn-info" ng-click="findReverse()">Reverse Name</button>
                <div>{{reversename}}</div>
            </div>

An angular application will render as shown below,

image

Let us understand difference between creating a service using the service() method and the factory() method.

  1. Using the service() method uses the function constructor and it returns the object or instance of the function to work with
  2. Using the factory() method uses the returned value of the function. It returns the value of the function returned after the execution

If we want to register a service using the function constructor, in that scenario we will use service() method to register the service. If we use factory() method to register the service it returns the value after execution of the service function. It can return any value like primitive value, function or object. So service() method returns the function object whereas factory() method can return any kind of value.

In further post we will talk about other ways of creating service. Now let us work on a full working example of using service in an angular app. We are going to create an application which will perform the followings,

  1. List students from the database
  2. Add a student to the database

Roughly architecture of the application can be drawn as shown below,

image

This post will not cover how to create a JSON based WCF REST Service. With the assumption that REST based service is already in place to retrieve the students and add a student, we will write the angular application.

The Service

var StudentService = angular.module('StudentService', [])
StudentService.factory('StudentDataOp', ['$http', function ($http) {

    var urlBase = 'http://localhost:2307/Service1.svc';
    var StudentDataOp = {};

    StudentDataOp.getStudents = function () {
        return $http.get(urlBase+'/GetStudents');
    };

    StudentDataOp.addStudent = function (stud) {
        return $http.post(urlBase + '/AddStudent', stud);
    };
    return StudentDataOp;

}]);

We are creating the service using the factory(). There are two methods in the service. getStudents fetch all the students using the $http.get whereas addStudent add a student using the $http.post. In the service we are using other inbuilt angular service $http to make the call to the service. To use the $http service, we have to pass this as dependency to the service factory() method.

Once service is created, let us create the controller which will use the service to perform the operations.

The Controller 

var myApp = angular.module('myApp', ['StudentService']);

myApp.controller('StudentController', function ($scope, StudentDataOp) {
    $scope.status;
    $scope.students;
    getStudents();

    function getStudents() {
        StudentDataOp.getStudents()
            .success(function (studs) {
                $scope.students = studs;
            })
            .error(function (error) {
                $scope.status = 'Unable to load customer data: ' + error.message;
            });
    }

    $scope.addStudent = function () {

        var stud = {
            ID: 145,
            FirstName: $scope.fname,
            LastName: $scope.lname
        };
        StudentDataOp.addStudent(stud)
            .success(function () {
                $scope.status = 'Inserted Student! Refreshing Student list.';
                $scope.students.push(stud);
            }).
            error(function (error) {
                $scope.status = 'Unable to insert Student: ' + error.message;
            });
    };
});

In the controller we are adding getStudents and addStudents functions to scope. As it is clear from the name that these functions are used to fetch students and add student respectively. As a dependency StudentSevice module is passed in the module and in the controller we are passing the StudentDataOp service as the dependency.

Other important thing to notice is that, we are creating student object to be added using the $scope object properties like fname and lname. These properties are set to the $scope on the view.

The View

View is very simple. StudentController is attached to the view. There are two section in the view. In first section we are taking user input to create the student. In the second section, in a table all the students are listed.

<div ng-controller="StudentController">
            <form class="well">
                <input type="text" name="fname" ng-model="fname" placeholder="first name" /> <br/>
                <input type="text" name="lname" ng-model="lname" placeholder="last name" />
                <br /><br/>
                <input type="button" value="add student" ng-click="addStudent()" class="btn btn-primary" />
            </form>
            <br/>
            <table class="table">
                <tr ng-repeat="s in students">
                    <td>{{ s.FirstName }}</td>
                    <td>{{ s.LastName }}</td>
                    <td>
                        <a href="#" class="btn btn-info" ng-click="edit(contact.id)">edit</a>
                        <a href="#" class="btn btn-danger" ng-click="delete(contact.id)">delete</a>
                    </td>
                </tr>
            </table>
        </div>

In the input form we are setting fname and lname properties on the $scope object and then calling addStudent() function of the controller to add a student to the database.

In the table using the ng-repeat directive all the students are listed. We have put two buttons for edit and delete. These buttons are not performing any task as of yet. In further posts we will add edit, delete and search functionality.

If you are following along the posts, may be you want to these functionality of your own and share experience with me.

On running the application, you will get form to add a student and all students listed in the table.

clip_image002

This is how you can create and use angularJS service in application. I hope you find this post useful. Thanks for reading. Happy coding.