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
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>
<!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>
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>
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>
Happy Coding
Tarun Kumar Chatterjee
Leave a comment