Agregando presupuesto y saldo
En esta sección aprenderemos a manejar el presupuesto y calcular el saldo disponible en nuestra aplicación de gastos.
Paso #1: Configuración inicial
Primero, vamos a crear las variables necesarias para manejar nuestro presupuesto y saldo. En el archivo app.ts
, agregaremos dos señales (signals):
presupuesto = signal(0); // Para almacenar el presupuesto total
saldo = signal(0); // Para llevar el control del dinero disponible
Ahora, agregaremos en nuestro HTML un formulario para que el usuario pueda ingresar su presupuesto y una sección para mostrar el saldo disponible:
<!-- Formulario para ingresar el presupuesto -->
<div class="form presupuesto">
<label for="presupuesto">Ingresa tu presupuesto:</label>
<input id="presupuesto" type="number" [(ngModel)]="presupuesto" />
<button> Listo </button>
</div>
<!-- Sección para mostrar el saldo -->
<div class="restante">
<p>Saldo disponible</p>
<p>{{saldo()}} Bs</p>
</div>
Aquí tienes el código completo de cómo debería quedar tu plantilla HTML:
<div class="contenedor-principal">
<div class="form presupuesto">
<label for="presupuesto">Ingresa tu presupuesto:</label>
<input id="presupuesto" type="number" [(ngModel)]="presupuesto()" />
<button> Listo </button>
</div>
<div class="form gasto">
<h3>Agrega tus gastos aquí</h3>
<div>
<label for="nombre-gasto">Nombre:</label>
<input
id="nombre-gasto"
type="text"
[(ngModel)]="nombreGasto"
(keyup.enter)="agregarGasto()"
/>
</div>
<div>
<label for="cantidad-gasto">Cantidad:</label>
<input
id="cantidad-gasto"
type="number"
[(ngModel)]="cantidadGasto"
(keyup.enter)="agregarGasto()"
/>
</div>
<button (click)="agregarGasto()">Listo</button>
</div>
<div class="contenedor-lista">
<div class="restante">
<p>Saldo disponible</p>
<p>{{saldo()}} Bs</p>
</div>
<div class="caja-lista">
<ul>
@for (gasto of gastos(); track $index) {
<li>
<p>{{gasto.nombre}}</p>
<div>
<span>{{gasto.cantidad}} Bs</span>
</div>
</li>
}
</ul>
</div>
</div>
</div>
Paso #2: Manejando el saldo inicial
Ahora crearemos una función que se encargará de guardar nuestro saldo inicial. Es importante entender que cuando comenzamos, nuestro saldo es igual a nuestro presupuesto (porque aún no hemos gastado nada).
Agregamos esta función en nuestro componente:
ingresarSaldoInicial(): void {
this.saldo.set(this.presupuesto()); // El saldo inicial es igual al presupuesto
}
Y modificamos nuestro HTML para llamar a esta función cuando el usuario presione Enter o el botón:
<input
id="presupuesto"
type="number"
[(ngModel)]="presupuesto"
(keyup.enter)="ingresarSaldoInicial()" <!-- Se ejecuta al presionar Enter -->
/>
<button (click)="ingresarSaldoInicial()"> Listo </button>
También necesitamos actualizar nuestra función agregarGasto
para que reste del saldo cada vez que agregamos un nuevo gasto:
agregarGasto(): void {
const gasto = new Gasto(this.nombreGasto(), this.cantidadGasto());
this.gastos.update((values) => [...values, gasto]);
this.saldo.set(this.saldo() - gasto.cantidad); // Restamos el gasto del saldo
this.nombreGasto.set('');
this.cantidadGasto.set(0);
}
Paso #3: Controlando el flujo de la aplicación
Es importante que el usuario ingrese primero su presupuesto antes de poder agregar gastos. Para lograr esto, usaremos una variable de control y la directiva @if
de Angular.
Primero, creamos una señal que nos ayudará a controlar esto:
saldoInicialIngresado = signal(false); // Inicialmente no se ha ingresado el saldo
ingresarSaldoInicial(): void {
this.saldo.set(this.presupuesto());
this.saldoInicialIngresado.set(true); // Marcamos que ya se ingresó el saldo
}
Luego, usamos la directiva @if
para mostrar u ocultar secciones de nuestra aplicación:
<!-- El formulario de gastos solo se muestra después de ingresar el presupuesto -->
@if(saldoInicialIngresado()) {
<div class="form gasto">...</div>
}
<!-- El saldo solo se muestra después de ingresar el presupuesto -->
@if(saldoInicialIngresado()) {
<div class="restante">...</div>
}
Así se verá nuestra aplicación antes de ingresar el presupuesto:
Y después de ingresar el presupuesto:
Paso #4: Mejorando la experiencia del usuario
Para hacer nuestra aplicación más intuitiva, vamos a:
- Ocultar el botón “Listo” después de ingresar el presupuesto
- Bloquear el campo de presupuesto para que no pueda modificarse
Para el botón, usamos @if
con el operador de negación !
:
<!-- El botón solo se muestra si NO se ha ingresado el saldo -->
@if(!saldoInicialIngresado()) {
<button (click)="ingresarSaldoInicial()">Listo</button>
}
Para el campo de presupuesto, usamos la propiedad readonly
:
<input
id="presupuesto"
type="number"
[(ngModel)]="presupuesto"
(keyup.enter)="ingresarSaldoInicial()"
[readonly]="saldoInicialIngresado()" <!-- Se bloquea después de ingresar el saldo -->
/>
El código completo de tu componente debería verse así:
export class App {
// Variables para el manejo de gastos
nombreGasto = signal('chocolate');
cantidadGasto = signal(10);
gastos = signal<Gasto[]>([]);
// Variables para el manejo del presupuesto
presupuesto = signal(0);
saldo = signal(0);
saldoInicialIngresado = signal(false);
// Función para agregar un nuevo gasto
agregarGasto(): void {
const gasto = new Gasto(this.nombreGasto(), this.cantidadGasto());
this.gastos.update((values) => [...values, gasto]);
this.saldo.set(this.saldo() - gasto.cantidad);
this.nombreGasto.set('');
this.cantidadGasto.set(0);
}
// Función para establecer el presupuesto inicial
ingresarSaldoInicial(): void {
this.saldo.set(this.presupuesto());
this.saldoInicialIngresado.set(true);
}
}