This commit is contained in:
Alberto Basalo 2015-10-25 11:21:42 +01:00
Родитель 2e1c8ae726 ecbc6bf8cd
Коммит 6d57c7c3c1
258 изменённых файлов: 1552 добавлений и 2907 удалений

Просмотреть файл

@ -16,7 +16,6 @@
<body class="container-fluid">
<header>
<h1>Hola Mundo AngularJS</h1>
</header>
<section>
<div>
@ -27,8 +26,10 @@
<br/>
<!--Interpolación en el contenido de una expresión {{entre llaves}} que usa una propiedadad del modelo-->
<div class="text-info">Hola {{ tuNombre }}, bienvenido al mundo de AngularJS !!!</div>
<!--Multiples Directivas ng-model para enlazar la vista con una ovarias propiedades del modelo-->
<input ng-model="numero1">
<input ng-model="numero2">
<input ng-model="numero2">
<h2>uno + uno son {{ numero1*1 + numero2*1}} </h2>
</section>
<footer>

Просмотреть файл

@ -1,49 +0,0 @@
"use strict";
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
var mimeTypes = {
"html": "text/html",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"
};
http.createServer(staticServer).listen(3000);
function staticServer(req, res) {
var pathname = url.parse(req.url).pathname;
if (pathname === "/") {
pathname = "index.html";
}
fileServer(res, pathname);
}
function fileServer(res, pathname) {
var filename = path.join(process.cwd(), pathname);
var extension = path.extname(filename).split(".")[1];
if (!extension) {
extension = "html";
filename += "." + extension;
}
fs.exists(filename, function (exists) {
if (!exists) {
notFound(res);
} else {
res.writeHead(200, {
'Content-Type': mimeTypes[extension]
});
fs.createReadStream(filename).pipe(res);
}
});
}
function notFound(res) {
res.writeHead(404, {
'Content-Type': 'text/html'
});
res.write("<html><head><meta charset='utf-8'></head><body><h1>404</h1> Nada por aquí</body></html>");
res.end();
}

Просмотреть файл

@ -1,49 +0,0 @@
"use strict";
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
var mimeTypes = {
"html": "text/html",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"
};
http.createServer(staticServer).listen(3000);
function staticServer(req, res) {
var pathname = url.parse(req.url).pathname;
if (pathname === "/") {
pathname = "index.html";
}
fileServer(res, pathname);
}
function fileServer(res, pathname) {
var filename = path.join(process.cwd(), pathname);
var extension = path.extname(filename).split(".")[1];
if (!extension) {
extension = "html";
filename += "." + extension;
}
fs.exists(filename, function (exists) {
if (!exists) {
notFound(res);
} else {
res.writeHead(200, {
'Content-Type': mimeTypes[extension]
});
fs.createReadStream(filename).pipe(res);
}
});
}
function notFound(res) {
res.writeHead(404, {
'Content-Type': 'text/html'
});
res.write("<html><head><meta charset='utf-8'></head><body><h1>404</h1> Nada por aquí</body></html>");
res.end();
}

Просмотреть файл

@ -0,0 +1,29 @@
// tenemos que cambiar la dependencia hacia el nuevo módulo
angular.module('cashFlow', ['ui.router']);
// las rutas ahora se maneja con el concepto de estado
angular.module('cashFlow').config(function ($stateProvider) {
// Las rutas pasan a ser opcionales,
// en la práctica sólo se usan si vienen de aplicaciones externas y por cuestiones de SEO
$stateProvider
.state('total', {
url: '/',
controller: 'CajaCtrl as caja',
templateUrl: 'total.html'
})
.state('nuevo', {
url: '/nuevo',
controller: 'CajaCtrl as caja',
templateUrl: 'nuevo.html'
})
.state('lista', {
url: '/lista',
controller: 'CajaCtrl as caja',
templateUrl: 'lista.html'
}).state('not-found', {
url: '*path',
templateUrl: 'not-found.html'
});
// realmente no existe un estado 'not found',
// pero puede llegar rutas no controladas
});

Просмотреть файл

@ -0,0 +1,28 @@
(function () {
angular.module('cashFlow').controller('CajaCtrl', cajaCtrl);
function cajaCtrl(movimientosFactory, maestrosService) {
var vm = this;
vm.titulo = "Controla tu Cash Flow";
vm.maestros = maestrosService.categorias;
vm.nuevoMovimiento = {
esIngreso: 1,
esGasto: 0,
importe: 0,
fecha: new Date()
};
vm.movimientos = movimientosFactory.getMovimientos();
vm.total = movimientosFactory.getTotal();
vm.guardarMovimiento = function () {
var auxCopyMov = angular.copy(vm.nuevoMovimiento);
movimientosFactory.postMovimiento(auxCopyMov);
vm.nuevoMovimiento.importe = 0;
}
vm.balance = movimientosFactory.balance;
vm.tipo = movimientosFactory.tipo;
}
}());

Просмотреть файл

@ -1,4 +1,4 @@
<html lang="es" ng-app="controlCajaApp">
<html lang="es" ng-app="cashFlow">
<head>
<title>Control de Caja</title>
@ -15,46 +15,40 @@
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top" name="navbar" role="navigation" ng-controller="MenuCtrl as menu">
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" ng-controller="MenuCtrl as menu">
<div class="navbar-inner">
<div class="container">
<ul class="nav navbar-nav">
<li ng-class="{ active: menu.isActive('total') }">
<a ui-sref="total" name="menu-total">Totales</a>
<!-- Los enlaces se formulan como estado, con ui-sref -->
<!-- Estos estados generan rutas, según la configuración -->
<!-- Pero internamente siempre trabajamos con estados -->
<a ui-sref="total">Totales</a>
</li>
<li ng-class="{ active: menu.isActive('nuevo') }">
<a ui-sref="nuevo" name="menu-nuevo">Nuevo</a>
<a ui-sref="nuevo">Nuevo</a>
</li>
<li ng-class="{ active: menu.isActive('lista') }">
<a ui-sref="lista" name="menu-lista">Lista</a>
<a ui-sref="lista">Lista</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- La directiva de ui-router es... ui-view-->
<div class="container text-center" style="padding-top:50px;" ui-view>
<!-- En este caso podríamos tener varias vista a la vez-->
<!-- Incluso estados anidados unos dentro de otros-->
</div>
<ab-pie-pagina></ab-pie-pagina>
<!-- JavaScript References -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-cookies.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<!-- En lugar del enrutador de AngularJS, usaremos uno de terceros, llamado ui-router-->
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
<!-- reorganización de referencias-->
<script src="_comun/app.js"></script>
<script src="_comun/states.js"></script>
<script src="_comun/appHttpLog.js"></script>
<script src="_comun/appSecurity.js"></script>
<script src="registro/registroCtrl.js"></script>
<script src="_comun/menuCtrl.js"></script>
<script src="controlcaja/cajaCtrl.js"></script>
<script src="movimiento/movimientoCtrl.js"></script>
<script src="data/movimientosFactory.js"></script>
<script src="data/maestrosFactory.js"></script>
<script src="filtros/filtros.js"></script>
<script src="directivas/directivas.js"></script>
<script src="directivas/valoracion/valoracion.js"></script>
<script src="app.js"></script>
<script src="menuCtrl.js"></script>
<script src="cajaCtrl.js"></script>
<script src="maestrosService.js"></script>
<script src="movimientosFactory.js"></script>
</body>
</html>

Просмотреть файл

Просмотреть файл

@ -0,0 +1,12 @@
(function () {
angular.module('cashFlow').service('maestrosService', maestrosService);
function maestrosService() {
this.categorias = {
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
};
}
}());

Просмотреть файл

@ -1,10 +1,10 @@
(function () {
angular.module('cashFlow').controller('MenuCtrl', menuCtrl);
// Ahora el sercvicio se llama $state
var menuCtrl = function ($state) {
function menuCtrl($state) {
this.isActive = function (estado) {
// Tiene funciones más amigables para consultar
return $state.is(estado);
}
}
angular.module('cashFlow').controller('MenuCtrl', menuCtrl);
}());

Просмотреть файл

@ -0,0 +1,43 @@
(function () {
angular.module('cashFlow').factory('movimientosFactory', movimientosFactory);
function movimientosFactory()  {
var movimientos = [];
var total = {
ingresos: 0,
gastos: 0
};
var result  =   {};
result.getMovimientos =   function ()  {
return movimientos;
};
result.getTotal =   function ()  {
return total;
};
result.postMovimiento =   function (movimiento)  {
movimientos.push(movimiento);
total.ingresos += movimiento.esIngreso * movimiento.importe;
total.gastos += movimiento.esGasto * movimiento.importe;
};
result.balance = function () {
return total.ingresos - total.gastos
}
result.tipo = function (movimiento) {
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
}
return result;
};
}());

Просмотреть файл

Просмотреть файл

@ -1,9 +1,6 @@
<section name="total">
<!--
<h1>{{ caja.titulo }}</h1>
<p class="lead">Comprueba de dónde viene y a dónde va tu dinero.</p>
-->
<ab-cabecera>Comprueba de dónde viene y a dónde va tu dinero.</ab-cabecera>
<div class="row-fluid">
<div class="row placeholders">
<div class="col-xs-8 col-sm-4 placeholder">

Просмотреть файл

@ -1,29 +0,0 @@
// tenemos que cambiar la dependencia hacia el nuevo módulo
angular.module('cashFlow', ['ui.router']);
// las rutas ahora se maneja con el concepto de estado
angular.module('cashFlow').config(function ($stateProvider) {
// Las rutas pasan a ser opcionales,
// en la práctica sólo se usan si vienen de aplicaciones externas y por cuestiones de SEO
$stateProvider
.state('total', {
url: '',
controller: 'CajaCtrl as caja',
templateUrl: 'total.html'
})
.state('nuevo', {
url: '/nuevo',
controller: 'CajaCtrl as caja',
templateUrl: 'nuevo.html'
})
.state('lista', {
url: '/lista',
controller: 'CajaCtrl as caja',
templateUrl: 'lista.html'
}).state('not-found', {
url: '*path',
templateUrl: 'not-found.html'
});
// realmente no existe un estado 'not found',
// pero puede llegar rutas no controladas
});

Просмотреть файл

@ -1,40 +0,0 @@
(function () {
var cajaCtrl = function (movimientosFactory) {
var vm = this;
vm.titulo = "Controla tu Cash Flow";
vm.maestros = {
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
};
vm.nuevoMovimiento = {
esIngreso: 1,
esGasto: 0,
importe: 0,
fecha: new Date()
};
vm.movimientos = movimientosFactory.getMovimientos();
vm.total = movimientosFactory.getTotal();
vm.guardarMovimiento = function () {
if(vm.nuevoMovimiento.esIngreso){
vm.total.ingresos += vm.nuevoMovimiento.importe;
}else{
vm.total.gastos += vm.nuevoMovimiento.importe;
}
var auxCopyMov = angular.copy(vm.nuevoMovimiento);
auxCopyMov.tipo = vm.tipo(auxCopyMov);
vm.movimientos.push(auxCopyMov);
vm.nuevoMovimiento.importe = 0;
}
vm.balance = function () {
return vm.total.ingresos - vm.total.gastos
}
vm.tipo = function (movimiento) {
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
}
}
angular.module('cashFlow').controller('CajaCtrl', cajaCtrl);
}());

Просмотреть файл

@ -1,50 +0,0 @@
<html lang="es" ng-app="cashFlow">
<head>
<title>Control de Caja</title>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<meta charset="utf-8" />
<meta lang="es" />
<meta name="description" content="Ejemplo Control de Caja en AngularJS por Alberto Basalo" />
<meta name="author" content="Alberto Basalo @ Ágora Binaria" />
<meta name="application-name" content="ControlAngularJS" />
<meta name="Keywords" content="AngularJS, ejemplo, tutorial, curso" />
<link rel="author" href="https://plus.google.com/+AlbertoBasalo71" />
<!-- Bootstrap core CSS -->
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" ng-controller="MenuCtrl as menu">
<div class="navbar-inner">
<div class="container">
<ul class="nav navbar-nav">
<li ng-class="{ active: menu.isActive('total') }">
<!-- Los enlaces se formulan como estado, con ui-sref -->
<!-- Estos estados generan rutas, según la configuración -->
<!-- Pero internamente siempre trabajamos con estados -->
<a ui-sref="total">Totales</a>
</li>
<li ng-class="{ active: menu.isActive('nuevo') }">
<a ui-sref="nuevo">Nuevo</a>
</li>
<li ng-class="{ active: menu.isActive('lista') }">
<a ui-sref="lista">Lista</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- La directiva de ui-router es... ui-view-->
<div class="container text-center" style="padding-top:50px;" ui-view >
<!-- En este caso podríamos tener varias vista a la vez-->
<!-- Incluso estados anidados unos dentro de otros-->
</div>
<!-- JavaScript References -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<!-- En lugar del enrutador de AngularJS, usaremos uno de terceros, llamado ui-router-->
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
<script src="app.js"></script>
<script src="menuCtrl.js"></script>
<script src="cajaCtrl.js"></script>
<script src="movimientosFactory.js"></script>
</body>
</html>

Просмотреть файл

@ -1,26 +0,0 @@
(function () {
var movimientosFactory =   function ()  {
var movimientos = [];
var total = {
ingresos: 0,
gastos: 0
};
var factory  =   {};
factory.getMovimientos =   function ()  {
return movimientos;
};
factory.getTotal =   function ()  {
return total;
};
factory.postMovimiento =   function (movimiento)  {
movimientos.push(movimiento);
total.ingresos += movimiento.esIngreso * movimiento.importe;
total.gastos += movimiento.esGasto * movimiento.importe;
};
return factory;
};
angular.module('cashFlow').factory('movimientosFactory', movimientosFactory);
}());

Просмотреть файл

@ -1,49 +0,0 @@
"use strict";
var http = require('http'),
url = require('url'),
path = require('path'),
fs = require('fs');
var mimeTypes = {
"html": "text/html",
"png": "image/png",
"js": "text/javascript",
"css": "text/css"
};
http.createServer(staticServer).listen(3000);
function staticServer(req, res) {
var pathname = url.parse(req.url).pathname;
if (pathname === "/") {
pathname = "index.html";
}
fileServer(res, pathname);
}
function fileServer(res, pathname) {
var filename = path.join(process.cwd(), pathname);
var extension = path.extname(filename).split(".")[1];
if (!extension) {
extension = "html";
filename += "." + extension;
}
fs.exists(filename, function (exists) {
if (!exists) {
notFound(res);
} else {
res.writeHead(200, {
'Content-Type': mimeTypes[extension]
});
fs.createReadStream(filename).pipe(res);
}
});
}
function notFound(res) {
res.writeHead(404, {
'Content-Type': 'text/html'
});
res.write("<html><head><meta charset='utf-8'></head><body><h1>404</h1> Nada por aquí</body></html>");
res.end();
}

Просмотреть файл

@ -0,0 +1,24 @@
// tenemos que agregar la dependencia hacia el nuevo módulo de filtros
angular.module('cashFlow', ['ui.router', 'abFiltros']);
angular.module('cashFlow').config(function ($stateProvider) {
$stateProvider
.state('total', {
url: '/',
controller: 'CajaCtrl as caja',
templateUrl: 'total.html'
})
.state('nuevo', {
url: '/nuevo',
controller: 'CajaCtrl as caja',
templateUrl: 'nuevo.html'
})
.state('lista', {
url: '/lista',
controller: 'CajaCtrl as caja',
templateUrl: 'lista.html'
}).state('not-found', {
url: '*path',
templateUrl: 'not-found.html'
});
});

Просмотреть файл

@ -0,0 +1,25 @@
(function () {
var cajaCtrl = function (movimientosFactory, maestrosService) {
var vm = this;
vm.titulo = "Controla tu Cash Flow";
vm.maestros = maestrosService.categorias;
vm.nuevoMovimiento = {
esIngreso: 1,
esGasto: 0,
importe: 0,
fecha: new Date()
};
vm.movimientos = movimientosFactory.getMovimientos();
vm.total = movimientosFactory.getTotal();
vm.guardarMovimiento = function () {
var auxCopyMov = angular.copy(vm.nuevoMovimiento);
movimientosFactory.postMovimiento(auxCopyMov);
vm.nuevoMovimiento.importe = 0;
}
vm.balance = movimientosFactory.balance;
vm.tipo = movimientosFactory.tipo;
}
angular.module('cashFlow').controller('CajaCtrl', cajaCtrl);
}());

Просмотреть файл

@ -1,6 +1,16 @@
(function () {
// Podemos usar una sintaxis fluida y declarar todo en una solo línea
// Atención a la declaración de un nuevo módulo genérico
angular.module('abFiltros', [])
.filter('abLimpiarCadena', limpiarCadena)
.filter('abRecortar', recortar)
.filter('abRellenarVacios', rellenarVacios)
.filter('abGranImporte', granImporte);
// Los filtros se declaran como funciones que a su vez devuelven... funciones
// Esas funciones internas se aplican sobre los valores,
// Tienen al menos un parámetro, que sirve de entrada
@ -73,12 +83,4 @@
};
return funcionFiltro;
}
// Podemos usar una sintaxis fluida y declarar todo en una solo línea
// Atención a la declaración de un nuevo módulo genérico
angular.module('abFiltros', [])
.filter('abLimpiarCadena', limpiarCadena)
.filter('abRecortar', recortar)
.filter('abRellenarVacios', rellenarVacios)
.filter('abGranImporte', granImporte);
}());

Просмотреть файл

@ -1,4 +1,4 @@
<html lang="es" ng-app="controlCajaApp">
<html lang="es" ng-app="cashFlow">
<head>
<title>Control de Caja</title>
@ -15,45 +15,37 @@
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top" name="navbar" role="navigation" ng-controller="MenuCtrl as menu">
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" ng-controller="MenuCtrl as menu">
<div class="navbar-inner">
<div class="container">
<ul class="nav navbar-nav">
<li ng-class="{ active: menu.isActive('total') }">
<a ui-sref="total" name="menu-total">Totales</a>
<a ui-sref="total">Totales</a>
</li>
<li ng-class="{ active: menu.isActive('nuevo') }">
<a ui-sref="nuevo" name="menu-nuevo">Nuevo</a>
<a ui-sref="nuevo">Nuevo</a>
</li>
<li ng-class="{ active: menu.isActive('lista') }">
<a ui-sref="lista" name="menu-lista">Lista</a>
<a ui-sref="lista">Lista</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container text-center" style="padding-top:50px;" ui-view>
</div>
<ab-pie-pagina></ab-pie-pagina>
<!-- JavaScript References -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-cookies.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
<script src="app.js"></script>
<script src="appHttpLog.js"></script>
<script src="appSecurity.js"></script>
<script src="registroCtrl.js"></script>
<script src="menuCtrl.js"></script>
<script src="cajaCtrl.js"></script>
<script src="movimientoCtrl.js"></script>
<script src="maestrosService.js"></script>
<script src="movimientosFactory.js"></script>
<script src="maestrosFactory.js"></script>
<!-- Incluir el fichero dónde se han programado los filtros-->
<script src="filtros.js"></script>
<!-- El fichero de directivas debe referenciarse -->
<script src="directivas.js"></script>
<script src="valoracion.js"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,29 @@
<section name="Lista">
<p class="lead">Estos son tus movimientos recientes.</p>
<br>
<label class="control-label" for="importe">Filtrar:</label>
<input type="text" name="filtro" placeholder="qué buscas?" class="input" ng-model="caja.valorBuscado">
<button class="btn-primary" ng-click="caja.valorCorte=0">Ver todos los movimientos</button>
<button class="btn-danger" ng-click="caja.valorCorte=1000">Sólo grandes movimientos</button>
<table class="table">
<thead>
<tr>
<th><a href="" ng-click="caja.campo = 'fecha'; caja.sentido = !caja.sentido ">Fecha</a>
</th>
<th>Tipo</th>
<th>Categoría</th>
<th><a href="" ng-click="caja.campo = 'importe'; caja.sentido = !caja.sentido ">Importe</a>
</th>
</tr>
</thead>
<tbody>
<!-- Usamos el filtro Gran Importe sobre un array -->
<tr ng-repeat="movimiento in caja.movimientos | abGranImporte:caja.valorCorte | filter:caja.valorBuscado | orderBy:caja.campo:caja.sentido">
<td class="text-left">{{movimiento.fecha | date}}</td>
<td class="text-left">{{movimiento.tipo}}</td>
<td class="text-left">{{movimiento.categoria}}</td>
<td class="text-left" ng-class="{'text-success': movimiento.tipo=='Ingreso', 'text-danger' : movimiento.tipo=='Gasto'}">{{movimiento.importe | number:2}} €</td>
</tr>
</tbody>
</table>
</section>

Просмотреть файл

@ -0,0 +1,10 @@
(function () {
angular.module('cashFlow').service('maestrosService', maestrosService);
function maestrosService() {
this.categorias = {
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
};
}
}());

Просмотреть файл

@ -0,0 +1,10 @@
(function () {
angular.module('cashFlow').controller('MenuCtrl', menuCtrl);
function menuCtrl($state) {
this.isActive = function (estado) {
return $state.is(estado);
}
}
}());

Просмотреть файл

@ -0,0 +1,38 @@
(function () {
angular.module('cashFlow').factory('movimientosFactory', movimientosFactory);
function movimientosFactory()  {
var movimientos = [];
var total = {
ingresos: 0,
gastos: 0
};
var result  =   {};
result.getMovimientos =   function ()  {
return movimientos;
};
result.getTotal =   function ()  {
return total;
};
result.postMovimiento =   function (movimiento)  {
movimientos.push(movimiento);
total.ingresos += movimiento.esIngreso * movimiento.importe;
total.gastos += movimiento.esGasto * movimiento.importe;
};
result.balance = function () {
return total.ingresos - total.gastos
}
result.tipo = function (movimiento) {
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
}
return result;
};
}());

Просмотреть файл

@ -0,0 +1,52 @@
<section name="nuevoMovimiento" class="row-fluid">
<form class="form-horizontal text-left">
<fieldset>
<div id="legend">
<legend class="">Introduce tus movimientos</legend>
</div>
<div class="row-fluid">
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="tipo">Tipo</label>
<div class="controls">
<div class="btn-group">
<button type="button" class="btn btn-success" ng-class="{'active':caja.nuevoMovimiento.esIngreso}" ng-click="caja.nuevoMovimiento.esIngreso=1; caja.nuevoMovimiento.esGasto=0">
<span ng-class="{'small':caja.nuevoMovimiento.esGasto}">+ Ingreso</span>
</button>
<button type="button" class="btn btn-danger" ng-class="{'active':caja.nuevoMovimiento.esGasto}" ng-click="caja.nuevoMovimiento.esIngreso=0; caja.nuevoMovimiento.esGasto=1">
<span ng-class="{'small':caja.nuevoMovimiento.esIngreso}">- Gasto</span>
</button>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="categ">Categoría</label>
<div class="controls">
<select ng-show="caja.nuevoMovimiento.esIngreso" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasIngresos"></select>
<select ng-show="caja.nuevoMovimiento.esGasto" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasGastos"></select>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="fecha">Fecha</label>
<div class="controls">
<input type="date" name="fecha" placeholder="" class="input" ng-model="caja.nuevoMovimiento.fecha">
</div>
</div>
<div class="control-group">
<label class="control-label" for="importe">Importe</label>
<div class="controls">
<input type="number" name="importe" placeholder="" class="input" ng-model="caja.nuevoMovimiento.importe">
</div>
</div>
</div>
</div>
<div class="text-right">
<button style="margin-top: 20px" type="button" class="btn btn-lg btn-primary" ng-click="caja.guardarMovimiento()">
<span>Guardar {{ caja.tipo(caja.nuevoMovimiento) }}</span>
</button>
</div>
</fieldset>
</form>
</section>

Просмотреть файл

@ -1,7 +1,4 @@
<!-- Cada sección tendrá su propia plantilla -->
<!-- No se especifíca el controlador, que será asignado por el enrutador -->
<section name="total">
<!-- Pero se supone un viweModel llamado caja-->
<h1>{{ caja.titulo }}</h1>
<p class="lead">Comprueba de dónde viene y a dónde va tu dinero.</p>
<div class="row-fluid">

24
08-directivas/app.js Normal file
Просмотреть файл

@ -0,0 +1,24 @@
// tenemos que agregar la dependencia hacia el nuevo módulo de directivas
angular.module('cashFlow', ['ui.router', 'abFiltros' , 'abComponentes', 'abDirectivas', 'abValoracion']);
angular.module('cashFlow').config(function ($stateProvider) {
$stateProvider
.state('total', {
url: '/',
controller: 'CajaCtrl as caja',
templateUrl: 'total.html'
})
.state('nuevo', {
url: '/nuevo',
controller: 'CajaCtrl as caja',
templateUrl: 'nuevo.html'
})
.state('lista', {
url: '/lista',
controller: 'CajaCtrl as caja',
templateUrl: 'lista.html'
}).state('not-found', {
url: '*path',
templateUrl: 'not-found.html'
});
});

25
08-directivas/cajaCtrl.js Normal file
Просмотреть файл

@ -0,0 +1,25 @@
(function () {
var cajaCtrl = function (movimientosFactory, maestrosService) {
var vm = this;
vm.titulo = "Controla tu Cash Flow";
vm.maestros = maestrosService.categorias;
vm.nuevoMovimiento = {
esIngreso: 1,
esGasto: 0,
importe: 0,
fecha: new Date()
};
vm.movimientos = movimientosFactory.getMovimientos();
vm.total = movimientosFactory.getTotal();
vm.guardarMovimiento = function () {
var auxCopyMov = angular.copy(vm.nuevoMovimiento);
movimientosFactory.postMovimiento(auxCopyMov);
vm.nuevoMovimiento.importe = 0;
}
vm.balance = movimientosFactory.balance;
vm.tipo = movimientosFactory.tipo;
}
angular.module('cashFlow').controller('CajaCtrl', cajaCtrl);
}());

Просмотреть файл

@ -0,0 +1,59 @@
(function () {
angular.module('abComponentes', [])
.directive('abPiePagina', piePagina)
.directive('abContenido', contenido)
.directive('abCabecera', cabecera)
.directive('abMenuNavegacion', menuNavegacion)
.directive('abFilaMovimiento', filaMovimiento);
// El uso más simple es crear directivas para usar como código reutilizable
function piePagina() {
return {
template: '<footer class="container"><hr/><p class="text-center">Desarrollado con AngularJS by Google. Por Alberto Basalo - <a href="http://agorabinaria.com">Ágora Binaria SL</a></p></footer>'
};
};
// las plantillas pueden tener directivas internas
function contenido() {
return {
template: '<div class="container text-center" style="padding-top:60px;" ui-view></div>'
};
};
// Dos mejoras, sacar el html a un fichero externo (tpl-directiva)
// Usar Transclude para reutilizar el contenido del usuario y hacer la vista más dinámica
// En este caso la plantilla debe usar la directiva ng-transclude
function cabecera() {
return {
transclude: true,
templateUrl: './tpl-cabecera.html'
};
};
// En este caso la directiva tiene presentación y lógica
// Asignamos el controlador a la vista desde la plantilla
function menuNavegacion(){
return {
templateUrl: './tpl-menu-navegacion.html',
controller : "MenuCtrl as menu"
};
}
// En este caso el cambio más siginificatico es el scope
// Funciona como un API para la directiva y recibe la info vía atributos
// Por otro lado en este caso hemos tenido que restringir el uso de la directiva
// Los elementos tr dentro de un table requieren definirse explícitamente
function filaMovimiento() {
return {
restrict: 'A',
templateUrl: './tpl-fila-movimiento.html',
scope: {
movimientoplantilla: "=movimientodirectiva"
}
};
}
}());

Просмотреть файл

@ -0,0 +1,56 @@
(function () {
angular.module('abDirectivas', [])
.directive('abSeleccionado', seleccionado)
.directive('input', seleccionado)
.directive('abPlugin', plugin);
// Otro uso de las directivas es extender la funionalidad del DOM sin importar los datos
// Este es el lugar donde manipular el DOM y jamás en los controladores
function seleccionado() {
return {
link: function (scope, element, attrs) {
element.bind('mouseenter', function () {
element.css('background-color', 'yellow');
});
element.bind('mouseleave', function () {
element.css('background-color', 'white');
});
}
};
}
// Ejemplo no funcional de cómo extender un plugin hecho a medida
function plugin() {
return {
link: function (scope, element, attrs) {
// Obtención de parámetros vía atributos
var init = scope.$eval(attrs.ngModel);
var min = scope.$eval(attrs.abPlugInMin);
var max = scope.$eval(attrs.abPlugInMax);
// Configuración básica
element.pluginInitMethod({
value: init,
min: min,
max: max,
tooltip: 'hide'
});
// Actualizar la vista cuando cambia el modelo
scope.$watch(attrs.ngModel, function (valor) {
element.pluginMethod('setValue', valor);
});
// Actualizar el modelo cuando cambia la vista
element.on('plugin_event', function (evento) {
scope.$apply(function () {
scope[attrs.ngModel] = evento.value;
});
});
}
}
}
}());

Просмотреть файл

@ -1,6 +1,16 @@
(function () {
// Podemos usar una sintaxis fluida y declarar todo en una solo línea
// Atención a la declaración de un nuevo módulo genérico
angular.module('abFiltros', [])
.filter('abLimpiarCadena', limpiarCadena)
.filter('abRecortar', recortar)
.filter('abRellenarVacios', rellenarVacios)
.filter('abGranImporte', granImporte);
// Los filtros se declaran como funciones que a su vez devuelven... funciones
// Esas funciones internas se aplican sobre los valores,
// Tienen al menos un parámetro, que sirve de entrada
@ -73,12 +83,4 @@
};
return funcionFiltro;
}
// Podemos usar una sintaxis fluida y declarar todo en una solo línea
// Atención a la declaración de un nuevo módulo genérico
angular.module('abFiltros', [])
.filter('abLimpiarCadena', limpiarCadena)
.filter('abRecortar', recortar)
.filter('abRellenarVacios', rellenarVacios)
.filter('abGranImporte', granImporte);
}());

39
08-directivas/index.html Normal file
Просмотреть файл

@ -0,0 +1,39 @@
<html lang="es" ng-app="cashFlow">
<head>
<title>Control de Caja</title>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<meta charset="utf-8" />
<meta lang="es" />
<meta name="description" content="Ejemplo Control de Caja en AngularJS por Alberto Basalo" />
<meta name="author" content="Alberto Basalo @ Ágora Binaria" />
<meta name="application-name" content="ControlAngularJS" />
<meta name="Keywords" content="AngularJS, ejemplo, tutorial, curso" />
<link rel="author" href="https://plus.google.com/+AlbertoBasalo71" />
<!-- Bootstrap core CSS -->
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<ab-menu-navegacion></ab-menu-navegacion>
<ab-contenido></ab-contenido>
<ab-pie-pagina></ab-pie-pagina>
<!-- JavaScript References -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
<script src="app.js"></script>
<script src="menuCtrl.js"></script>
<script src="cajaCtrl.js"></script>
<script src="maestrosService.js"></script>
<script src="movimientosFactory.js"></script>
<script src="filtros.js"></script>
<!-- Incluir los fichero donde se han programado las directivas-->
<script src="componentes.js"></script>
<script src="directivas.js"></script>
<script src="valoracion.js"></script>
</body>
</html>

31
08-directivas/lista.html Normal file
Просмотреть файл

@ -0,0 +1,31 @@
<section name="Lista">
<div ab-cabecera>Estos son tus movimientos recientes.</div>
<br>
<label class="control-label" for="importe">Filtrar:</label>
<input type="text" name="filtro" placeholder="qué buscas?" class="input" ng-model="caja.valorBuscado">
<button class="btn-primary" ng-click="caja.valorCorte=0">Ver todos los movimientos</button>
<button class="btn-danger" ng-click="caja.valorCorte=1000">Sólo grandes movimientos</button>
<table class="table">
<thead>
<tr>
<th><a href="" ng-click="caja.campo = 'fecha'; caja.sentido = !caja.sentido ">Fecha</a>
</th>
<th>Tipo</th>
<th>Categoría</th>
<th><a href="" ng-click="caja.campo = 'importe'; caja.sentido = !caja.sentido ">Importe</a>
</th>
</tr>
</thead>
<tbody>
<!-- Sustituimos el contenido de cada fila por un componente -->
<tr ng-repeat="movimientoRepeater in caja.movimientos | abGranImporte:caja.valorCorte | filter:caja.valorBuscado | orderBy:caja.campo:caja.sentido"
ab-fila-movimiento movimientodirectiva="movimientoRepeater"
ab-seleccionado
>
<!-- El componente abFilaMovimiento recibe un parámetro vía atributos
los nombres de las variables pueden ser distintos a nivel de cliente, directiva y plantilla-->
<!-- La directiva abSeleccionado cambia el fondo cuando el ratón está encima-->
</tr>
</tbody>
</table>
</section>

Просмотреть файл

@ -0,0 +1,10 @@
(function () {
angular.module('cashFlow').service('maestrosService', maestrosService);
function maestrosService() {
this.categorias = {
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
};
}
}());

10
08-directivas/menuCtrl.js Normal file
Просмотреть файл

@ -0,0 +1,10 @@
(function () {
angular.module('cashFlow').controller('MenuCtrl', menuCtrl);
function menuCtrl($state) {
this.isActive = function (estado) {
return $state.is(estado);
}
}
}());

Просмотреть файл

@ -0,0 +1,38 @@
(function () {
angular.module('cashFlow').factory('movimientosFactory', movimientosFactory);
function movimientosFactory()  {
var movimientos = [];
var total = {
ingresos: 0,
gastos: 0
};
var result  =   {};
result.getMovimientos =   function ()  {
return movimientos;
};
result.getTotal =   function ()  {
return total;
};
result.postMovimiento =   function (movimiento)  {
movimientos.push(movimiento);
total.ingresos += movimiento.esIngreso * movimiento.importe;
total.gastos += movimiento.esGasto * movimiento.importe;
};
result.balance = function () {
return total.ingresos - total.gastos
}
result.tipo = function (movimiento) {
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
}
return result;
};
}());

Просмотреть файл

@ -0,0 +1,3 @@
<section name="total">
<ab-cabecera>No se ha encontrado lo que buscabas</ab-cabecera>
</section>

69
08-directivas/nuevo.html Normal file
Просмотреть файл

@ -0,0 +1,69 @@
<section name="nuevoMovimiento" class="row-fluid">
<ab-cabecera>Introduce tus movimientos</ab-cabecera>
<form class="form-horizontal text-left">
<fieldset>
<div class="row-fluid">
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="tipo">Tipo</label>
<div class="controls">
<div class="btn-group">
<button type="button" class="btn btn-success" ng-class="{'active':caja.nuevoMovimiento.esIngreso}" ng-click="caja.nuevoMovimiento.esIngreso=1; caja.nuevoMovimiento.esGasto=0">
<span ng-class="{'small':caja.nuevoMovimiento.esGasto}">+ Ingreso</span>
</button>
<button type="button" class="btn btn-danger" ng-class="{'active':caja.nuevoMovimiento.esGasto}" ng-click="caja.nuevoMovimiento.esIngreso=0; caja.nuevoMovimiento.esGasto=1">
<span ng-class="{'small':caja.nuevoMovimiento.esIngreso}">- Gasto</span>
</button>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="categ">Categoría</label>
<div class="controls">
<select ng-show="caja.nuevoMovimiento.esIngreso" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasIngresos"></select>
<select ng-show="caja.nuevoMovimiento.esGasto" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasGastos"></select>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="fecha">Fecha</label>
<div class="controls">
<input type="date" name="fecha" placeholder="" class="input" ng-model="caja.nuevoMovimiento.fecha">
</div>
</div>
<div class="control-group">
<label class="control-label" for="importe">Importe</label>
<div class="controls">
<input type="number" name="importe" placeholder="" class="input" ng-model="caja.nuevoMovimiento.importe">
</div>
</div>
</div>
<div class="row-fluid">
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="texto">Texto</label>
<div class="controls">
<input type="text" name="texto" class="input" ng-model="caja.nuevoMovimiento.texto">
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="valoracion">Valoración</label>
<div class="controls">
<!--Uso de la directiva abValoracion para solicitar las estrellas de valoración-->
<div ab-valoracion valor="caja.nuevoMovimiento.valoracion" max="10" solo-lectura="false"></div>
</div>
</div>
</div>
</div>
</div>
<div class="text-right">
<button style="margin-top: 20px" type="button" class="btn btn-lg btn-primary" ng-click="caja.guardarMovimiento()">
<span>Guardar {{ caja.tipo(caja.nuevoMovimiento) }}</span>
</button>
</div>
</fieldset>
</form>
</section>

Просмотреть файл

@ -1,9 +1,5 @@
<!-- Cada sección tendrá su propia plantilla -->
<!-- No se especifíca el controlador, que será asignado por el enrutador -->
<section name="total">
<!-- Pero se supone un viweModel llamado caja-->
<h1>{{ caja.titulo }}</h1>
<p class="lead">Comprueba de dónde viene y a dónde va tu dinero.</p>
<ab-cabecera>Comprueba de dónde viene y a dónde va tu dinero.</ab-cabecera>
<div class="row-fluid">
<div class="row placeholders">
<div class="col-xs-8 col-sm-4 placeholder">

Просмотреть файл

@ -0,0 +1,6 @@
<div class="panel panel-primary">
<div class="panel-heading">Cash Flow</div>
<div class="panel-body">
<div class="lead" ng-transclude></div>
</header>
</div>

Просмотреть файл

@ -0,0 +1,10 @@
<td class="text-left">{{movimientoplantilla.fecha | date}}</td>
<td class="text-left">{{movimientoplantilla.tipo}}</td>
<td class="text-left">{{movimientoplantilla.categoria}}</td>
<td class="text-left" ng-class="{'text-success': movimientoplantilla.tipo=='Ingreso', 'text-danger' : movimientoplantilla.tipo=='Gasto'}">
{{movimientoplantilla.importe | number:2}} €
</td>
<td class="text-left">
<!--Uso de la directiva abValoracion para mostrar las estrellas en modo solo lectura-->
<ab-valoracion valor="movimientoplantilla.valoracion" max="10" solo-lectura="true"></ab-valoracion>
</td>

Просмотреть файл

@ -0,0 +1,18 @@
<!--Se elimina la referencia al controlador, y se establece desde la directiva-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" >
<div class="navbar-inner">
<div class="container">
<ul class="nav navbar-nav">
<li ng-class="{ active: menu.isActive('total') }">
<a ui-sref="total">Totales</a>
</li>
<li ng-class="{ active: menu.isActive('nuevo') }">
<a ui-sref="nuevo">Nuevo</a>
</li>
<li ng-class="{ active: menu.isActive('lista') }">
<a ui-sref="lista">Lista</a>
</li>
</ul>
</div>
</div>
</nav>

Просмотреть файл

@ -0,0 +1,8 @@
<span ng-repeat="estrella in valoracion.estrellas" ng-click="valoracion.marcar($index)">
<span class="lead"
ng-class=
"{'text-danger h3': estrella.marcada,
'text-muted small': !estrella.marcada}">
<b><u>*</u></b>
</span>
</span>

Просмотреть файл

@ -0,0 +1,48 @@
(function () {
angular.module('abValoracion', [])
.directive('abValoracion', valoracion);
function valoracion() {
return {
restrict: 'AE',
templateUrl: './tpl-valoracion.html',
scope: {
valor: '=',
max: '@',
soloLectura: '@'
},
bindToController: true,
controllerAs: "valoracion",
controller: valoracionCtrl
}
}
function valoracionCtrl() {
var vm = this;
/** responde al click en una estrella */
vm.marcar = function (indice) {
if (vm.soloLectura && vm.soloLectura === 'true') {
return;
}
vm.valor = indice + 1;
actualizar();
};
/** para empezar iniciamos los datos según lo recibido en el scope */
actualizar();
/** actualiza los datos para repintar la vista */
function actualizar() {
if (!vm.valor) vm.valor = 1;
vm.estrellas = [];
for (var i = 0; i < vm.max; i++) {
var estrella = {
marcada: (i < vm.valor)
};
vm.estrellas.push(estrella);
}
};
}
}());

Просмотреть файл

@ -1,8 +0,0 @@
(function () {
var menuCtrl = function ($state) {
this.isActive = function (estado) {
return $state.is(estado);
}
}
angular.module('controlCajaApp').controller('MenuCtrl',menuCtrl);
}());

Просмотреть файл

@ -0,0 +1,3 @@
angular.module('cashFlow', ['ui.router', 'abFiltros' , 'abComponentes', 'abDirectivas', 'abValoracion']);

Просмотреть файл

@ -0,0 +1,54 @@
(function () {
//cambios en las rutas relativas de las plantillas
angular.module('abDirectivas', [])
.directive('abSeleccionado', seleccionado)
.directive('input', seleccionado)
.directive('abPlugin', plugin);
function seleccionado() {
return {
link: function (scope, element, attrs) {
element.bind('mouseenter', function () {
element.css('background-color', 'yellow');
});
element.bind('mouseleave', function () {
element.css('background-color', 'white');
});
}
};
}
function plugin() {
return {
link: function (scope, element, attrs) {
var init = scope.$eval(attrs.ngModel);
var min = scope.$eval(attrs.abPlugInMin);
var max = scope.$eval(attrs.abPlugInMax);
element.pluginInitMethod({
value: init,
min: min,
max: max,
tooltip: 'hide'
});
scope.$watch(attrs.ngModel, function (valor) {
element.pluginMethod('setValue', valor);
});
element.on('plugin_event', function (evento) {
scope.$apply(function () {
scope[attrs.ngModel] = evento.value;
});
});
}
}
}
}());

Просмотреть файл

@ -1,5 +1,11 @@
(function () {
angular.module('abFiltros', [])
.filter('abLimpiarCadena', limpiarCadena)
.filter('abRecortar', recortar)
.filter('abRellenarVacios', rellenarVacios)
.filter('abGranImporte', granImporte);
function limpiarCadena() {
var funcionFiltro = function (cadena) {
if (cadena) {
@ -62,10 +68,4 @@
};
return funcionFiltro;
}
angular.module('abFiltros', [])
.filter('abLimpiarCadena', limpiarCadena)
.filter('abRecortar', recortar)
.filter('abRellenarVacios', rellenarVacios)
.filter('abGranImporte', granImporte);
}());

Просмотреть файл

@ -0,0 +1,10 @@
(function () {
angular.module('cashFlow').service('maestrosService', maestrosService);
function maestrosService() {
this.categorias = {
categoriasIngresos: ['Nómina', 'Ventas', 'Intereses Depósitos'],
categoriasGastos: ['Hipotéca', 'Compras', 'Impuestos']
};
}
}());

Просмотреть файл

@ -0,0 +1,38 @@
(function () {
angular.module('cashFlow').factory('movimientosFactory', movimientosFactory);
function movimientosFactory()  {
var movimientos = [];
var total = {
ingresos: 0,
gastos: 0
};
var result  =   {};
result.getMovimientos =   function ()  {
return movimientos;
};
result.getTotal =   function ()  {
return total;
};
result.postMovimiento =   function (movimiento)  {
movimientos.push(movimiento);
total.ingresos += movimiento.esIngreso * movimiento.importe;
total.gastos += movimiento.esGasto * movimiento.importe;
};
result.balance = function () {
return total.ingresos - total.gastos
}
result.tipo = function (movimiento) {
return movimiento.esIngreso && 'Ingreso' || 'Gasto'
}
return result;
};
}());

Просмотреть файл

@ -0,0 +1,22 @@
//cambios en las rutas relativas de las vistas
angular.module('cashFlow').config(function ($stateProvider) {
$stateProvider
.state('total', {
url: '/',
controller: 'CajaCtrl as caja',
templateUrl: './app/states/total.html'
})
.state('nuevo', {
url: '/nuevo',
controller: 'CajaCtrl as caja',
templateUrl: './app/states/nuevo.html'
})
.state('lista', {
url: '/lista',
controller: 'CajaCtrl as caja',
templateUrl: './app/states/lista.html'
}).state('not-found', {
url: '*path',
templateUrl: './app/states/not-found.html'
});
});

Просмотреть файл

@ -0,0 +1,48 @@
(function () {
//cambios en las rutas relativas de las vistas
angular.module('abComponentes', [])
.directive('abPiePagina', piePagina)
.directive('abContenido', contenido)
.directive('abCabecera', cabecera)
.directive('abMenuNavegacion', menuNavegacion)
.directive('abFilaMovimiento', filaMovimiento);
function piePagina() {
return {
template: '<footer class="container"><hr/><p class="text-center">Desarrollado con AngularJS by Google. Por Alberto Basalo - <a href="http://agorabinaria.com">Ágora Binaria SL</a></p></footer>'
};
};
function contenido() {
return {
template: '<div class="container text-center" style="padding-top:60px;" ui-view></div>'
};
};
function cabecera() {
return {
transclude: true,
templateUrl: './app/components/tpl-cabecera.html'
};
};
function menuNavegacion() {
return {
templateUrl: './app/components/tpl-menu-navegacion.html',
controller: "MenuCtrl as menu"
};
}
function filaMovimiento() {
return {
restrict: 'A',
templateUrl: './app/components/tpl-fila-movimiento.html',
scope: {
movimientoplantilla: "=movimientodirectiva"
}
};
}
}());

Просмотреть файл

@ -0,0 +1,10 @@
(function () {
angular.module('cashFlow').controller('MenuCtrl', menuCtrl);
function menuCtrl($state) {
this.isActive = function (estado) {
return $state.is(estado);
}
}
}());

Просмотреть файл

@ -0,0 +1,6 @@
<div class="panel panel-primary">
<div class="panel-heading">Cash Flow</div>
<div class="panel-body">
<div class="lead" ng-transclude></div>
</header>
</div>

Просмотреть файл

@ -0,0 +1,10 @@
<td class="text-left">{{movimientoplantilla.fecha | date}}</td>
<td class="text-left">{{movimientoplantilla.tipo}}</td>
<td class="text-left">{{movimientoplantilla.categoria}}</td>
<td class="text-left" ng-class="{'text-success': movimientoplantilla.tipo=='Ingreso', 'text-danger' : movimientoplantilla.tipo=='Gasto'}">
{{movimientoplantilla.importe | number:2}} €
</td>
<td class="text-left">
<!--Uso de la directiva abValoracion para mostrar las estrellas en modo solo lectura-->
<ab-valoracion valor="movimientoplantilla.valoracion" max="10" solo-lectura="true"></ab-valoracion>
</td>

Просмотреть файл

@ -0,0 +1,18 @@
<!--Se elimina la referencia al controlador, y se establece desde la directiva-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation" >
<div class="navbar-inner">
<div class="container">
<ul class="nav navbar-nav">
<li ng-class="{ active: menu.isActive('total') }">
<a ui-sref="total">Totales</a>
</li>
<li ng-class="{ active: menu.isActive('nuevo') }">
<a ui-sref="nuevo">Nuevo</a>
</li>
<li ng-class="{ active: menu.isActive('lista') }">
<a ui-sref="lista">Lista</a>
</li>
</ul>
</div>
</div>
</nav>

Просмотреть файл

@ -0,0 +1,8 @@
<span ng-repeat="estrella in valoracion.estrellas" ng-click="valoracion.marcar($index)">
<span class="lead"
ng-class=
"{'text-danger h3': estrella.marcada,
'text-muted small': !estrella.marcada}">
<b><u>*</u></b>
</span>
</span>

Просмотреть файл

@ -0,0 +1,48 @@
(function () {
angular.module('abValoracion', [])
.directive('abValoracion', valoracion);
function valoracion() {
return {
restrict: 'AE',
templateUrl: './app/components/valoracion/tpl-valoracion.html',
scope: {
valor: '=',
max: '@',
soloLectura: '@'
},
bindToController: true,
controllerAs: "valoracion",
controller: valoracionCtrl
}
}
function valoracionCtrl() {
var vm = this;
/** responde al click en una estrella */
vm.marcar = function (indice) {
if (vm.soloLectura && vm.soloLectura === 'true') {
return;
}
vm.valor = indice + 1;
actualizar();
};
/** para empezar iniciamos los datos según lo recibido en el scope */
actualizar();
/** actualiza los datos para repintar la vista */
function actualizar() {
if (!vm.valor) vm.valor = 1;
vm.estrellas = [];
for (var i = 0; i < vm.max; i++) {
var estrella = {
marcada: (i < vm.valor)
};
vm.estrellas.push(estrella);
}
};
}
}());

Просмотреть файл

@ -0,0 +1,25 @@
(function () {
var cajaCtrl = function (movimientosFactory, maestrosService) {
var vm = this;
vm.titulo = "Controla tu Cash Flow";
vm.maestros = maestrosService.categorias;
vm.nuevoMovimiento = {
esIngreso: 1,
esGasto: 0,
importe: 0,
fecha: new Date()
};
vm.movimientos = movimientosFactory.getMovimientos();
vm.total = movimientosFactory.getTotal();
vm.guardarMovimiento = function () {
var auxCopyMov = angular.copy(vm.nuevoMovimiento);
movimientosFactory.postMovimiento(auxCopyMov);
vm.nuevoMovimiento.importe = 0;
}
vm.balance = movimientosFactory.balance;
vm.tipo = movimientosFactory.tipo;
}
angular.module('cashFlow').controller('CajaCtrl', cajaCtrl);
}());

Просмотреть файл

@ -0,0 +1,31 @@
<section name="Lista">
<div ab-cabecera>Estos son tus movimientos recientes.</div>
<br>
<label class="control-label" for="importe">Filtrar:</label>
<input type="text" name="filtro" placeholder="qué buscas?" class="input" ng-model="caja.valorBuscado">
<button class="btn-primary" ng-click="caja.valorCorte=0">Ver todos los movimientos</button>
<button class="btn-danger" ng-click="caja.valorCorte=1000">Sólo grandes movimientos</button>
<table class="table">
<thead>
<tr>
<th><a href="" ng-click="caja.campo = 'fecha'; caja.sentido = !caja.sentido ">Fecha</a>
</th>
<th>Tipo</th>
<th>Categoría</th>
<th><a href="" ng-click="caja.campo = 'importe'; caja.sentido = !caja.sentido ">Importe</a>
</th>
</tr>
</thead>
<tbody>
<!-- Sustituimos el contenido de cada fila por un componente -->
<tr ng-repeat="movimientoRepeater in caja.movimientos | abGranImporte:caja.valorCorte | filter:caja.valorBuscado | orderBy:caja.campo:caja.sentido"
ab-fila-movimiento movimientodirectiva="movimientoRepeater"
ab-seleccionado
>
<!-- El componente abFilaMovimiento recibe un parámetro vía atributos
los nombres de las variables pueden ser distintos a nivel de cliente, directiva y plantilla-->
<!-- La directiva abSeleccionado cambia el fondo cuando el ratón está encima-->
</tr>
</tbody>
</table>
</section>

Просмотреть файл

@ -0,0 +1,3 @@
<section name="total">
<ab-cabecera>No se ha encontrado lo que buscabas</ab-cabecera>
</section>

Просмотреть файл

@ -0,0 +1,69 @@
<section name="nuevoMovimiento" class="row-fluid">
<ab-cabecera>Introduce tus movimientos</ab-cabecera>
<form class="form-horizontal text-left">
<fieldset>
<div class="row-fluid">
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="tipo">Tipo</label>
<div class="controls">
<div class="btn-group">
<button type="button" class="btn btn-success" ng-class="{'active':caja.nuevoMovimiento.esIngreso}" ng-click="caja.nuevoMovimiento.esIngreso=1; caja.nuevoMovimiento.esGasto=0">
<span ng-class="{'small':caja.nuevoMovimiento.esGasto}">+ Ingreso</span>
</button>
<button type="button" class="btn btn-danger" ng-class="{'active':caja.nuevoMovimiento.esGasto}" ng-click="caja.nuevoMovimiento.esIngreso=0; caja.nuevoMovimiento.esGasto=1">
<span ng-class="{'small':caja.nuevoMovimiento.esIngreso}">- Gasto</span>
</button>
</div>
</div>
</div>
<div class="control-group">
<label class="control-label" for="categ">Categoría</label>
<div class="controls">
<select ng-show="caja.nuevoMovimiento.esIngreso" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasIngresos"></select>
<select ng-show="caja.nuevoMovimiento.esGasto" name="categoria" ng-model="caja.nuevoMovimiento.categoria" ng-options="categoria for categoria in caja.maestros.categoriasGastos"></select>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="fecha">Fecha</label>
<div class="controls">
<input type="date" name="fecha" placeholder="" class="input" ng-model="caja.nuevoMovimiento.fecha">
</div>
</div>
<div class="control-group">
<label class="control-label" for="importe">Importe</label>
<div class="controls">
<input type="number" name="importe" placeholder="" class="input" ng-model="caja.nuevoMovimiento.importe">
</div>
</div>
</div>
<div class="row-fluid">
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="texto">Texto</label>
<div class="controls">
<input type="text" name="texto" class="input" ng-model="caja.nuevoMovimiento.texto">
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="control-group">
<label class="control-label" for="valoracion">Valoración</label>
<div class="controls">
<!--Uso de la directiva abValoracion para solicitar las estrellas de valoración-->
<div ab-valoracion valor="caja.nuevoMovimiento.valoracion" max="10" solo-lectura="false"></div>
</div>
</div>
</div>
</div>
</div>
<div class="text-right">
<button style="margin-top: 20px" type="button" class="btn btn-lg btn-primary" ng-click="caja.guardarMovimiento()">
<span>Guardar {{ caja.tipo(caja.nuevoMovimiento) }}</span>
</button>
</div>
</fieldset>
</form>
</section>

Просмотреть файл

@ -0,0 +1,34 @@
<section name="total">
<ab-cabecera>Comprueba de dónde viene y a dónde va tu dinero.</ab-cabecera>
<div class="row-fluid">
<div class="row placeholders">
<div class="col-xs-8 col-sm-4 placeholder">
<h1>
<span class="label label-success">
{{ caja.total.ingresos | number:2 }} €
</span>
</h1>
<h4>Total ingresos</h4>
<span class="text-muted">Acumulado</span>
</div>
<div class="col-xs-8 col-sm-4 placeholder">
<h1>
<span class="label label-danger">
{{ caja.total.gastos | number:2 }} €
</span>
</h1>
<h4>Total gastos</h4>
<span class="text-muted">Acumulado</span>
</div>
<div class="col-xs-8 col-sm-4 placeholder">
<h1>
<span class="label " ng-class="{'label-success': caja.balance()>=0 , 'label-danger' : caja.balance()<0}">
{{ caja.balance() | number:2 }} €
</span>
</h1>
<h4>Balance</h4>
<span class="text-muted">Ingresos-Gastos</span>
</div>
</div>
</div>
</section>

Просмотреть файл

@ -0,0 +1,40 @@
<html lang="es" ng-app="cashFlow">
<head>
<title>Control de Caja</title>
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
<meta charset="utf-8" />
<meta lang="es" />
<meta name="description" content="Ejemplo Control de Caja en AngularJS por Alberto Basalo" />
<meta name="author" content="Alberto Basalo @ Ágora Binaria" />
<meta name="application-name" content="ControlAngularJS" />
<meta name="Keywords" content="AngularJS, ejemplo, tutorial, curso" />
<link rel="author" href="https://plus.google.com/+AlbertoBasalo71" />
<!-- Bootstrap core CSS -->
<link href="http://getbootstrap.com/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<ab-menu-navegacion></ab-menu-navegacion>
<ab-contenido></ab-contenido>
<ab-pie-pagina></ab-pie-pagina>
<!-- JavaScript References -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<script src="http://angular-ui.github.io/ui-router/release/angular-ui-router.min.js"></script>
<!-- Cambios para reflejar la nueva posición de los ficheros -->
<script src="app/app.js"></script>
<script src="app/common/states.js"></script>
<script src="app/common/maestrosService.js"></script>
<script src="app/common/movimientosFactory.js"></script>
<script src="app/common/filtros.js"></script>
<script src="app/common/directivas.js"></script>
<script src="app/components/componentes.js"></script>
<script src="app/components/menuCtrl.js"></script>
<script src="app/components/valoracion/valoracion.js"></script>
<script src="app/states/cajaCtrl.js"></script>
</body>
</html>

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше