Tutorial de AngularJS: Tema 7 – Una calculadora

AngularJS

Hola de nuevo!

Ha pasado ya bastante tiempo desde que hicimos nuestra última entrada. Temas laborales y de otra índole han hecho que no podamos prestar la atención que necesita el blog.

Tal como prometimos en el post anterior, hoy vamos a dedicarnos a hacer una calculadora básica para practicar lo poco que hemos aprendido hasta ahora. Allá vamos…

Primero de todo, vamos a pegar todo el código para luego ir desgranando lo más importante:

calculator.html
<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>eXpert Designs - Calculadora en AngularJs</title>
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
 <script src="app.js"></script>
 <link rel="stylesheet" href="style.css">
</head>
<body>
 <div ng-app="mainApp" align="center">
 <h2>eXpert Designs - Calculadora en AngularJs</h2>
 <div ng-controller="CalCtrl">
 <table width="250px" height="300px" align="center">
 <tr>
 <td colspan="4">
 <input type="text" style="text-align:center; width: 236px; height:30px" name="output" id="res" value="{{output}}" disabled = "disabled">
 </td>
 </tr>
 <tr>
 <td colspan="4">
 <button title="Number 1" style="width:56px" ng-click="press('1')">1</button>
 <button title="Number 2" style="width:56px" ng-click="press('2')">2</button>
 <button title="Number 3" style="width:56px" ng-click="press('3')">3</button>
 <button title="Operate +" style="width:56px" ng-click='operate("+")' >+</button>
 </td>
 </tr>
 <tr>
 <td colspan="4">
 <button style="width:56px" ng-click="press('4')">4</button>
 <button style="width:56px" ng-click="press('5')">5</button>
 <button style="width:56px" ng-click="press('6')">6</button>
 <button title="Operate -" style="width:56px" ng-click='operate("-")' >-</button>
 </td>
 </tr>
 <tr>
 <td colspan="4">
 <button title="Number 7" style="width:56px" ng-click="press('7')">7</button>
 <button title="Number 8" style="width:56px" ng-click="press('8')">8</button>
 <button title="Number 9" style="width:56px" ng-click="press('9')">9</button>
 <button title="Operate *" style="width:56px" ng-click='operate("*")' >x</button>
 </td>
 </tr>
 <tr>
 <td>
 <button title="Number 0" style="width:56px" ng-click="press('0')">0</button>
 <button title="." style="width:56px" ng-click="press('.')">.</button>
 <button title="Clear all" style="width:56px" ng-click="output = '0'">C</button>
 <button title="Operate /" style="width:56px" ng-click='operate("/")' >/</button>
 </td>
 </tr>
 <tr>
 <td>
 <button style="width:175px" ng-click="equal()">=</button>
 <button title="Delete" style="width:56px" ng-click="press('x')">&#9003;</button>
 </td>
 </tr>
 </table>
 <span align="center" style="color:red">{{msg}}</span>
 </div>
 </div>
</body>
</html>
style.css
table, th, td {
 border: 1px solid grey;
 border-collapse: collapse;
 padding: 5px;
}

table tr:nth-child(odd) {
 background-color: #f2f2f2;
}

table tr:nth-child(even) {
 background-color: #ffffff;
}
app.js
var mainApp = angular.module("mainApp", []);
 mainApp.controller('CalCtrl', function($scope) {
 $scope.output = "0";
 $scope.curIndex = 0;
 $scope.result = 0;
 
 $scope.checkInput = function(num) {
 var tmp = true;
 if($scope.result != 0) {
 $scope.result = 0;
 $scope.output = "0";
 tmp = true;
 }
 if(angular.equals('+', num) || 
 angular.equals('-', num) ||
 angular.equals('*', num) || 
 angular.equals('/', num)) {
 var index = "+|-|*|/".indexOf($scope.output.charAt($scope.output.length - 1));
 if(index >= 0) {
 tmp = false;
 $scope.msg = "Solo se puede indicar un operador cada vez.";
 }
 $scope.curIndex = $scope.output.length + 1;
 } else {
 tmp = true;
 if($scope.output.substring($scope.curIndex).length < 10) {
 if(angular.equals(num, ".")) {
 var k = 0;
 for(var j = 0; j < $scope.output.substring($scope.curIndex).length; j++){
 if(angular.equals(".", $scope.output.substring($scope.curIndex).charAt(j))) {
 k = k + 1;
 }
 }
 if(k >= 1){
 $scope.msg = "Solo se puede indicar un decimal '.' por numero!";
 tmp = false;
 }
 } else {
 tmp = true;
 }
 } else {
 $scope.msg = "No se pueden indicar mas de 10 digitos cada vez!";
 tmp = false;
 }
 }
 return tmp;
 }
 
 $scope.operate = function(op) {
 if($scope.checkInput(op)) {
 $scope.output = $scope.output + op;
 }
 }
 
 
 $scope.press = function(num) {
 if($scope.checkInput(num)) {
 if(angular.equals(num, 'x')){
 $scope.output = $scope.output.slice(0 , $scope.output.length - 1); 
 } else {
 if (angular.equals($scope.output, "0")) {
 $scope.output = "";
 $scope.msg = "";
 $scope.output += num;
 } else if (angular.equals(".", $scope.output)){
 $scope.msg = "";
 $scope.output = "0.";
 $scope.output += num;
 } else {
 $scope.msg = "";
 $scope.output += num;
 }
 }
 } else {
 if(angular.equals(num, 'x')){
 $scope.msg = "";
 $scope.output = $scope.output.slice(0 , $scope.output.length - 1); 
 }
 }
 }
 
 $scope.equal = function() {
 var isOpEnd = "+|-|*|/".indexOf($scope.output.charAt($scope.output.length - 1));
 if(isOpEnd >= 0) {
 $scope.msg = "Primero debes completar la formula!";
 } else if(eval($scope.output) == 0){
 $scope.output = "0";
 } else {
 $scope.msg = "";
 $scope.result = eval($scope.output);
 $scope.output = $scope.result;
 }
 }
});

En un principio, lo más destacable es la separación de ficheros (html, css y js). De este modo no lo tenemos todo en un único fichero y lo hacemos más legible.

Si nos centramos en el index.html, veremos lo siguiente:

  • En el div que almacena todo el cuerpo hemos hecho referencia a nuestro módulo mainApp con ng-app=”mainApp”.
  • Dentro, hemos creado varias filas y columnas para definir la forma de la calculadora. En cada uno de los botones se hace un ng-click=”acción donde se llama a cada acción a realizar (operate, press, equals, etc.).
  • Por último, tendremos un texto donde mostraremos los mensajes de error en caso de producirse (dos operadores simultáneos, poner un operador sin tener un número previo, poner más de 10 dígitos…).

El style.css da el formato a los elementos del html, por lo que no hay mucho más que decir.

En el app.js es donde tendremos toda la lógica de la aplicación web:

  • Definiremos el módulo mainApp. Sobre este módulo crearemos el controlador CalcCtrl.
  • Inicializaremos las variables que usaremos en la aplicación y definiremos las funciones con las que se va a comunicar la vista:
    • checkInput: comprobará que los datos y los operadores que se están pasando son correctos. En caso de error lo mostrará en el texto de mensajes.
    • operate: si checkInput no devuelve un error, añade el operador pasado por parámetros a la variable de la operación.
    • press: si checkInput no devuelve un error, añade el valor pasado por parámetros a la variable de la operación. En caso de ser ‘x’, quita el último valor u operación añadida.
    • equal: comprueba que la fórmula sea correcta, la aplica (mediante la función eval) y la muestra en el resultado.

Y el resultado es el siguiente:

Esperamos que os haya gustado. Si tenéis dudas podéis preguntarlas en los comentarios.

Saludos!

Deja un comentario

A %d blogueros les gusta esto: