Introduction to Angular JS

Tarun Kumar Chatterjee
 
Net – Technology Specialist
April 19, 2016
 
Rate this article
 
Views
7514

AngularJS is a JavaScript framework which simplifies binding JavaScript objects with HTML UI elements.

To download the angular package into your project you can run the following command: Install-Package angularjs

Let us try to understand some of the basics implementations on Angular JS.

Two way data binding:

We have a two way data binding when a model variable is bound to a HTML element that can both change and display the value of the variable. In general, we could have more than one HTML element bound to the same variable. We use the ng-model directive to bind a model variable to the HTML element that can not only display its value, but also change it.

In the example, we bind the name model variables to a HTML input element. When the page is loaded, the value of the input element is initialized to the respective model variable and whenever the user types something in an input, the value of the model variable is modified as well (two ways).

 <!DOCTYPE html>
 <html>
 <head>
  <title>AngularJS Demo</title>
  
 <link href="~/Content/bootstrap.css" rel="stylesheet" />
 <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
 <script src="~/Scripts/angular.js"></script>
 <script >
     //defining module
     var myapp = angular.module('myapp', []);
     myapp.controller('testContoller', testController);
 
     function testController($scope){
         var vm = this;
         vm.name = "Tarun Chatterjee";        
     }
 </script>
 </head>
 <body ng-app="myapp">
     <div  ng-controller="testContoller">
         <p>Name: {{name}}</p>
         <input type="text" ng-model="name">
     </div> 
 </body>
 </html>
 

Output: Typing in the text field will automatically reflect the value on “name” place holder

clip_image002

Custom directive:

In angular custom directive the best practice is to follow camel casing and that also with at least two letter’s. In camel case naming convention we start with a small letter, followed by a capital letter for every word.

If you are making a one letter prefix like “copyright” it’s very much possible that tomorrow if HTML team creates a tag with the same name, it will clash with your custom directive. That’s why angular team recommends camel case which inserts a “-“ in between to avoid further collision with future HTML tag’s.

In angular if it is like: copyRight then in html we will have to write as copy-right

 <!DOCTYPE html>
 <html>
 <head>
  <title>AngularJS Demo</title>
  
 <link href="~/Content/bootstrap.css" rel="stylesheet" />
 <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
 <script src="~/Scripts/angular.js"></script>
     
 <script  type="text/javascript">
 
     //defining module
     var myapp = angular.module('myapp', []);
     
     myapp.directive('copyRight', function () {
         var directive = {};
         directive.template = '@@CopyRight test.com';
         return directive;
                
     });        
     
    
 </script>
 </head>
 
 <body ng-app="myapp">    
 <div copy-right></div>     
 
 </body>
 </html>
 
 

clip_image004

 <!DOCTYPE html>
 <html>
 <head>
     <title>AngularJS Demo</title>
 
     <link href="~/Content/bootstrap.css" rel="stylesheet" />
     <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
     <script src="~/Scripts/angular.js"></script>
 
     <script type="text/javascript">
 
         //defining module
         var myapp = angular.module('myapp', []);
 
         myapp.controller('MyController', ['$scope', function($scope) {
             $scope.customer = {
                 name: 'Tarun Chatterjee',
                 address: 'Kolkata'
             };
         }])
         .directive('myDirective', function () {
             var directive = {};
             directive.restrict = 'A';
             directive.template = 'Name: {{customer.name}} Address: {{customer.address}}'; // we need use templateUrl instead of template if we want to refer a html file  
             return directive;
         });
 
     </script>
 </head>
 
 <body ng-app="myapp">
     <div ng-controller="MyController">
         <div my-directive></div>
     </div>
 
 </body>
 </html>
 
 

clip_image006

Best Practice: Unless your template is very small, it’s typically better to break it apart into its own HTML file and load it with the templateUrl option.

· The “restrict” property is set to “E” which means that this directive can only be used at element level as shown in the code snippet below.

<userinfo></userinfo>

· If you try to use it at an attribute level as shown in the below code it will not work.

<div userinfo></div>

So “E” for element, “A” for attribute & “C” for CSS.

I want custom directives to be applied on element as well as attributes directive.restrict = ‘EA’;

AEC – is for either attribute or element or class name

Directive that Manipulates the DOM

Directives that want to modify the DOM typically use the link option to register DOM listeners as well as update the DOM. It is executed after the template has been cloned and is where directive logic will be put.

 <!DOCTYPE html>
 <html>
 <head>
     <title>AngularJS Demo</title>
 
     <link href="~/Content/bootstrap.css" rel="stylesheet" />
     <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
     <script src="~/Scripts/angular.js"></script>
 
     <script type="text/javascript">
 
         //defining module
         var myapp = angular.module('myapp', []);
 
         myapp.controller('MyController', ['$scope', function($scope) {
             $scope.format = 'M/d/yy h:mm:ss a';
         }])
        .directive('myCurrentTime', ['$interval', 'dateFilter', function ($interval, dateFilter) {
 
            function link(scope, element, attrs) {
                var format,
                    timeoutId;
 
                function updateTime() {
                    element.text(dateFilter(new Date(), format));
                }
 
                scope.$watch(attrs.myCurrentTime, function (value) {
                    format = value;
                    updateTime();
                });
 
               
                // start the UI update process; save the timeoutId for canceling
                timeoutId = $interval(function () {
                    updateTime(); // update DOM
                }, 1000);
            }
 
            return {
                link: link
            };
        }]);
 
     </script>
 </head>
 
 <body ng-app="myapp">
    
     <div ng-controller="MyController">
         Date format: <input type="text" ng-model="format"> <hr/>
         Current time is: <span my-current-time="format"></span>
     </div>
 
 </body>
 </html>
 
 

clip_image008

Link can make a directive that reacts to events on its elements. That we will look into the form validation section.

$watch():

The $scope.watch() function creates a watch of some variable. When you register a watch you pass two functions as parameters to the $watch() function:

  • A value function
  • A listener function

This example value function returns the $scope variable scope.data.myVar. If the value of this variable changes, a different value will be returned & AngularJS will call the listener function.

 $scope.$watch(function (scope) { return scope.data.myVar },
               function (newValue, oldValue) {
                   document.getElementById("").innerHTML =
                       "" + newValue + "";
               }
              );
 
 

$digest():

The $scope.$digest() function iterates through all the watches in the $scope object, and its child $scope objects (if it has any). When $digest() iterates over the watches, it calls the value function for each watch. If the value returned by the value function is different than the value it returned the last time it was called, the listener function for that watch is called.

You may encounter some corner cases where AngularJS does not call the $digest() function for you. You will usually detect that by noticing that the data bindings do not update the displayed values. In that case, call $scope.$digest() and it should work. Or, you can perhaps use $scope.$apply() instead which I will explain in the next section.

$apply():

The $scope.$apply() function takes a function as parameter which is executed, and after that $scope.$digest() is called internally. That makes it easier for you to make sure that all watches are checked, and thus all data bindings refreshed. Here is an $apply() example:

 $scope.$apply(function () {
 $scope.data.myVar = "Another value";
 });
 

Form Validation:

It should be noted that while client-side validation plays an important role in providing good user experience, it can easily be bypassed and thus cannot be trusted. Server-side validation is still necessary for a secure application.

To allow styling of form as well as controls, ngModel adds the following CSS classes:

  • ng-valid: the model is valid
  • ng-invalid: the model is invalid
  • ng-valid-[key]: for each valid key added by $setValidity
  • ng-invalid-[key]: for each invalid key added by $setValidity
  • ng-pristine: the control hasn’t been interacted with yet
  • ng-dirty: the control has been interacted with
  • ng-touched: the control has been blurred
  • ng-untouched: the control hasn’t been blurred
  • ng-pending: any $asyncValidators are unfulfilled

In the example both user.name and user.email are required, but are rendered with red background only after the input is blurred (loses focus). This ensures that the user is not distracted with an error until after interacting with the control & failing to satisfy its validity.

 <!DOCTYPE html>
 <html>
 <head>
     <title>AngularJS & Bootstrap Form Validation</title>
 
     <link href="~/Content/bootstrap.css" rel="stylesheet" />
     <link href="~/Content/bootstrap-theme.css" rel="stylesheet" />
     <script src="~/Scripts/angular.js"></script>
     <script src="~/Scripts/angular.min.js"></script>
     <script src="~/Scripts/jquery-1.9.1.min.js"></script>
     <style type="text/css">
         .css-form input.ng-invalid.ng-touched {
             background-color: #FA787E;
         }
 
         .css-form input.ng-valid.ng-touched {
             background-color: #78FA89;
         }
     </style>
     <script>
 
         //defining module
         var myapp = angular.module('myapp', []);
 
 
         //creating custom directive
         myapp.directive('ngCompare', function () {
             return {
                 require: 'ngModel',
                 link: function (scope, currentEl, attrs, ctrl) {
                     var comparefield = $('[name="password"]'); //getting first element
                     compareEl = angular.element(comparefield);
 
                     //current field key up
                     currentEl.on('keyup', function () {
                         if (compareEl.val() != "") {
                             var isMatch = currentEl.val() === compareEl.val();
                             ctrl.$setValidity('compare', isMatch);
                             scope.$digest();
                         }
                     });
 
                     //Element to compare field key up
                     compareEl.on('keyup', function () {
                         if (currentEl.val() != "") {
                             var isMatch = currentEl.val() === compareEl.val();
                             ctrl.$setValidity('compare', isMatch);
                             scope.$digest();
                         }
                     });
                 }
             }
         });
 
         // create angular controller
         myapp.controller('mainController', function ($scope) {
             // Set the 'submitted' flag to true
             $scope.submitted = true;
 
             $scope.countryList = [
             { CountryId: 1, Name: 'India' },
             { CountryId: 2, Name: 'USA' }
             ];
 
             $scope.cityList = [];
 
             $scope.$watch('user.country', function (newVal, oldVal) {
 
                 if (newVal == 1)
                     $scope.cityList = [
                     { CountryId: 1, CityId: 1, Name: 'Kolkata' },
                     { CountryId: 1, CityId: 2, Name: 'Delhi' }];
                 else if (newVal == 2)
                     $scope.cityList = [
                     { CountryId: 2, CityId: 3, Name: 'Denver' },
                     { CountryId: 2, CityId: 4, Name: 'NewYork' }];
                 else
                     $scope.cityList = [];
             });
 
             // function to submit the form after all validation has occurred 
             $scope.submitForm = function () {
 
 
                 if ($scope.userForm.$valid) {
                     alert("Form is valid!");
                 }
                 else {
                     alert("Please correct errors!");
                 }
             };
         });
 
     </script>
 </head>
 <body ng-app="myapp">
 
 
     <div class="container" ng-controller="mainController">
         <div class="col-sm-8 col-sm-offset-2">
 
             <!-- PAGE HEADER -->
             <div class="page-header">
                 <h1>AngularJS Form Validation</h1>
             </div>
 
             <!-- FORM : YOU CAN DISABLE, HTML5 VALIDATION BY USING "novalidate" ATTRIBUTE-->
             <form name="userForm" ng-submit="submitForm()" novalidate>
 
                 <div novalidate class="css-form" class="form-group">
                     <label>Name</label>
                     <input type="text" name="name" class="form-control" ng-model="user.name" placeholder="Your Name" ng-required="true">
                     <p ng-show="userForm.username.$error.required && (userForm.username.$dirty || submitted)" class="help-block">Name is required.</p>
                 </div>
 
 
                 <!-- USERNAME -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.username.$invalid && (userForm.username.$dirty || submitted)}">
                     <label>Username</label>
                     <input type="text" name="username" class="form-control" ng-model="user.username" placeholder="Your Username" ng-minlength="3" ng-maxlength="8" ng-required="true">
                     <p ng-show="userForm.username.$error.required && (userForm.username.$dirty || submitted)" class="help-block">You username is required.</p>
                     <p ng-show="userForm.username.$error.minlength && (userForm.username.$dirty || submitted)" class="help-block">Username is too short.</p>
                     <p ng-show="userForm.username.$error.maxlength && (userForm.username.$dirty || submitted)" class="help-block">Username is too long.</p>
                 </div>
 
                 <!-- PASSWORD -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.password.$invalid && (userForm.password.$dirty || submitted)}">
                     <label>Password</label>
                     <input type="Password" name="password" class="form-control" ng-model="user.password" placeholder="Your Password" ng-required="true">
                     <p ng-show="userForm.password.$error.required && (userForm.password.$dirty || submitted)" class="help-block">Your password is required.</p>
                 </div>
 
                 <!-- CONFIRM PASSWORD -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.confirmPassword.$invalid && (userForm.confirmPassword.$dirty || submitted)}">
                     <label>Confirm Password</label>
                     <input type="Password" name="confirmPassword" class="form-control" ng-model="user.confirmPassword" placeholder="Confirm Your Password" ng-compare="password" ng-required="true">
                     <p ng-show="userForm.confirmPassword.$error.required && (userForm.confirmPassword.$dirty || submitted)" class="help-block">Your confirm password is required.</p>
                     <p ng-show="userForm.confirmPassword.$error.compare && (userForm.confirmPassword.$dirty || submitted)" class="help-block">Confirm password doesnot match.</p>
                 </div>
 
                 <!-- EMAIL -->
                 <div novalidate class="css-form" class="form-group">
                     <label>Email</label>
                     <input type="email" name="email" class="form-control" ng-model="user.email" placeholder="Your Email Address" ng-required="true">
                     <p ng-show="userForm.email.$error.required && (userForm.email.$dirty || submitted)" class="help-block">Email is required.</p>
                     <p ng-show="userForm.email.$error.email && (userForm.email.$dirty || submitted)" class="help-block">Enter a valid email.</p>
                 </div>
 
                 <!-- CONTACTNO -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.contactno.$invalid && (userForm.contactno.$dirty || submitted) }">
                     <label>ContactNo</label>
                     <input type="text" name="contactno" class="form-control" ng-model="user.contactno" placeholder="Your Contact No" ng-pattern="/^[789]d{9}$/" maxlength="10">
                     <p ng-show="userForm.contactno.$error.pattern && (userForm.contactno.$dirty || submitted)" class="help-block">Enter a valid contactno.</p>
                 </div>
 
                 <!-- COUNTRY -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.country.$invalid && (userForm.country.$dirty || submitted)}">
                     <label>Country</label>
                     <select name="country" class="form-control"
                         ng-model="user.country"
                         ng-options="country.CountryId as country.Name for country in countryList"
                         ng-required="true">
                         <option value=''>Select</option>
                     </select>
                     <p ng-show="userForm.country.$error.required && (userForm.country.$dirty || submitted)" class="help-block">Select country.</p>
                 </div>
 
                 <!-- CITY -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.city.$invalid && (userForm.city.$dirty || submitted)}">
                     <label>City</label>
                     <select name="city" class="form-control"
                         ng-model="user.city"
                         ng-options="city.CityId as city.Name for city in cityList"
                         ng-required="true">
                         <option value=''>Select</option>
                     </select>
                     <p ng-show="userForm.city.$error.required && (userForm.city.$dirty || submitted)" class="help-block">Select city.</p>
                 </div>
 
                 <!-- TERMS & CONDITIONS -->
                 <div class="form-group" ng-class="{ 'has-error' : userForm.terms.$invalid && (userForm.terms.$dirty || submitted)}">
                     <label>Accept Terms & Conditions</label>
                     <input type="checkbox" value="" name="terms" ng-model="user.terms" ng-required="true" />
                     <p ng-show="userForm.terms.$error.required && (userForm.terms.$dirty || submitted)" class="help-block">Accept terms & conditions.</p>
                 </div>
 
                 <!-- ng-disabled FOR ENABLING AND DISABLING SUBMIT BUTTON -->
                 <!--<button type="submit" class="btn btn-primary" ng-disabled="userForm.$invalid">Register</button>-->
                 <button type="submit" class="btn btn-primary">Register</button>
             </form>
         </div>
     </div>
     <br />
 </body>
 </html>
 

clip_image010

clip_image012

Happy Coding

Tarun Kumar Chatterjee

Author Info

Tarun Kumar Chatterjee
 
Net – Technology Specialist
 
Rate this article
 
Tarun has been working in IT Industry for over 12+ years. He holds a B-tech degree. He is passionate about learning and sharing the tricks and tips in Azure, .Net ...read more
 

Leave a comment