Using Custom Directive To Build an EMI Calculator in AngularJS using JQueryUI

Rajnilari2015
Posted by in AngularJS category on for Intermediate level | Points: 250 | Views : 633 red flag
Rating: 4 out of 5  
 1 vote(s)

In this article, we will build a simple EMI Calculator. For building that, we will use JQueryUI slider, normal html textbox components, and AngularJS custom directive will facilitate for communicating between these two components.


 Download source code for Using Custom Directive To Build an EMI Calculator in AngularJS using JQueryUI

Introduction

In this article, we will build a simple EMI Calculator. For building that, we will use JQueryUI slider, normal html textbox components, and AngularJS custom directive will facilitate for communicating between these two components. The final output should be

Straight to Program

Let us first create a folder structure as under

We have the "*.js" files inside the "js" folder and "*.css" inside the "css" folder.

Let us first create the controller "EMICalculatorCtrl.js" and it's content is as under

var emiApp = angular.module("emiApp", []);

emiApp.controller("EMIController", function($scope, $http){

	$scope.loanAmount = 1;
	$scope.interestRate = 1;
	$scope.loanTenure = 1;
	$scope.EMI=0.0;	
  	$scope.ishidden= !true;       

    //this function contains the EMI logic
    $scope.calculateEMI = function(){

    	var loanamt = $scope.loanAmount;    	
    	var intrest=$scope.interestRate;
    	var repaytrm=$scope.loanTenure;

    	//EMI calculation logic    	
    	var rate1 = (parseFloat(intrest)/100)/12;
    	var rate = 1+rate1;
    	var interestRate = Math.pow(rate,repaytrm);
    	var E1 = loanamt*rate1*interestRate;
    	var E2 = interestRate-1;
    	var EMI = (E1/E2);    	
    	var total_payable=EMI*repaytrm;
    	var total_interest=(total_payable-loanamt);

    	//Values to display
    	$scope.EMI=display2Decimals(EMI); 
      	$scope.interestPayable = display2Decimals(total_interest);
      	$scope.totalPayable=display2Decimals(total_payable);
      	$scope.ishidden=!false; } //end function calculateEMI

    //this function resets the values to their default
    $scope.reset = function(){

        	$scope.loanAmount = 1;
    		$scope.interestRate = 1;
    		$scope.loanTenure = 1;
    		$scope.EMI=0.0;
    		$scope.interestPayable=0.0;
    		$scope.totalPayable=0.0;
    		$scope.ishidden=!true; } // end function reset

}); //end controller

It's a pretty simple controller whose name is "EMIController" and contains the logic for EMI Calculation. The function calculateEMI holds the logic. The reset function resets the values to their default. The $scope.ishidden is a boolean property that controls the visibility of a particular section in the template which we will encounter shortly.

The display2Decimals(x) is the function that resides under the "utility.js" and it displays 2 decimals. It is as under

function display2Decimals(x){ 
  return Number(parseFloat(x)).toFixed(2);
}

Now let us create the view part by creating a "EMICalculator.html" as under

<!DOCTYPE html>
<html>
	<head>
	  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
	  <title>EMI Calculator</title> 
		<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/themes/smoothness/jquery-ui.css">
		<link href="css/custom.css" rel="stylesheet" type="text/css">		
	  	<script data-require="angular.js@1.4.0-beta.6" data-semver="1.4.0-beta.6" src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>   
   		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
   		<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/jquery-ui.min.js"></script>
   		<script src="js/utility.js"></script>	
	  	<script src="js/EMICalculatorCtrl.js"></script>	  
	</head>

	<body ng-app="emiApp" ng-controller="EMIController">
		<div><h2><font color="blue"><u>EMI Calculator</u></font></h2> </div>
		<table border="1">
			<tr>
				<td bgcolor="D1D39B">
					<table>
							<tr>
								<td colspan="3">
									<font color="blue" size="4">Let us understand the financial needs</font>
								</td>
							</tr>
							<tr>
								<td>Loan Amount:</td>										
			        			<td><div ng-model="loanAmount" style="width:200px;"></div></td>
			        			<td><input type= "text" ng-model="loanAmount" id="txtLoanAmount">  ?</td>
							</tr>
							<tr>
			        			<td>Interest Rate</td>
			        			<td><div ng-model="interestRate" style="width:200px;"></div></td>
			        			<td><input type= "text" ng-model="interestRate" id="txtIR">  %</td>
	    					</tr>
	    					<tr>
			        			<td>Loan Tenure(months):</td>
			        			<td><div ng-model="loanTenure" style="width:200px;"></div></td>
			        			<td><input type= "text" ng-model="loanTenure" id="txtLT">  Months</td>
	    					</tr>
	    					<tr>
								<td></td>
								<td></td>
			        			<td>
						        	<input type="button" id="btnCalculate" value="Calculate" class="button blueButton" ng-click="calculateEMI()"/>
						        	<input type="button" id="btnReset" value="Reset" class="button grayButton" ng-click="reset()"/>
			        			</td>
							</tr>
	    				</table>
				</td>
				<td ng-show="ishidden" bgcolor="9BD3BD">
					<table>
						<tr>
							<td colspan="3"><font color="blue" size="4">An indicative amount to pay</font></td>
						</tr>
						<tr>
							<td>Monthly Payment (EMI)</td>
							<td>?<input type="text" id="txtEMI" value="{{EMI}}"></td>
						</tr>
						<tr>
				        		<td>Total Interest Payable</td>
				        		<td>?<input type="text" id="txtIP" value="{{interestPayable}}"></td>
		    				</tr>
						<tr>
							<td>Total Payment(Principal + Interest)</td>
							<td>?<input type="text" id="txtTP" value="{{totalPayable}}"></td>
						</tr>						
					</table>
				</td>
			</tr>
		</table>			 
	</body>
</html>

If we run at this point the view will be

So our slider does not appear. However, we can still perform the operation as under by entering some numeric values and clicking on the Calculate button in which case the result will be

Reset button equally does it job properly

But we need to have the slider to appear and make a two way binding. For that reason, we need to create a directive. The reason is by using directives, we can modify the behavior of a specific DOM element as well as add a new custom element to the DOM. For a detail explanation of AngularJS directive, please read this article. Our directive is as under

emiApp.directive('jqSlider', function() {
  return {
    restrict: 'A',
      scope: {
          ngModel: '=',
          max: '=?'
      },
    link: function(scope, elem, attrs) {
    	scope.$watch('ngModel', function(val) {
      	$(elem).slider("value", val);
      })
      
      return $(elem).slider({
        range: "min",
        animate: true,
        max: scope.max || 100,
        value: scope.ngModel,
        slide: function(event, ui) {
          return scope.$apply(function(){
            scope.ngModel = ui.value;
          });
        }
      });
    }
  };
});

Our directive whose name is jqSlider is a typical isolated scope directive that is using a jQuery plugin and is confined to attributes. scope.ngModel is passed in to the directive through the matching attribute ng-model in the html. The '=' makes it a 2 way binding to it's parent. The link function creates listeners on the DOM model. These listeners keep the view and the model in sync at all times. $watch helps to listen for $scope changes. As for the slider it is a jQuery UI slider and the options like animate, range, max,value, slide etc are documented in their API. The slide( event, ui ) triggers on every mouse move during slide. The value provided in the event as ui.value represents the value that the handle will have as a result of the current movement. Max range can be changed using max option. If max field won't be specified in element it will set a maximum to 100.

Now it's time to bind the same to our view and below is the way we have done

<tr>
	<td>Loan Amount:</td>										
	<td><div jq:slider ng-model="loanAmount" style="width:200px;" max="100000"></div></td>
	<td><input type= "text" ng-model="loanAmount" id="txtLoanAmount">  ?</td>
</tr>
<tr>
	<td>Interest Rate</td>
	<td><div jq-slider ng-model="interestRate" style="width:200px;" max="50"></div></td>
	<td><input type= "text" ng-model="interestRate" id="txtIR">  %</td>
</tr>
<tr>
	<td>Loan Tenure(months):</td>
	<td><div jq_slider ng-model="loanTenure" style="width:200px;"></div></td>
	<td><input type= "text" ng-model="loanTenure" id="txtLT">  Months</td>
</tr>

Since we know that, we can use the directive in the view by separating the camel case name (since a directive name is specified in camel case) of the directive, either using a dash, colon, or underscore so we have used it in multiple ways like jq:slider, jq-slider, jq_slider for the demonstration purpose.

Now let us run the application again

So our Slider control is now visible in the DOM structure and we can start playing with our little calculator.

References

Creating Custom Directives

Conclusion

In this article we have learnt the uses of custom directives in AngularJS which facilitates for communicating between JQueryUI and normal Html controls, two way binding and finally build a simple EMI Calculator. Hope this will be useful. Thanks for reading. Zipped file attached.

Recommendation
Read Pagination in Aurelia after this article.
Page copy protected against web site content infringement by Copyscape

About the Author

Rajnilari2015
Full Name: Niladri Biswas (RNA Team)
Member Level: Platinum
Member Status: Member,Microsoft_MVP,MVP
Member Since: 3/17/2015 2:41:06 AM
Country: India
-- Thanks & Regards, RNA Team


Login to vote for this post.

Comments or Responses

Posted by: Sheonarayan on: 10/5/2016 | Points: 25
Thanks for the article Niladri.

I think there are two ways to calculate Interest component for duration, Yearly and Monthly.

Adding option to enter Yearly or Monthly duration will make this app complete.

Posted by: Rajnilari2015 on: 10/5/2016 | Points: 25
@Sheo Sir, Sure, I will update the same

Login to post response

Comment using Facebook(Author doesn't get notification)