This article has been localized into Spanish by the community.
TODO List: el Controller
En los artículos previos, configuramos la base de datos para nuestra aplicación TODO List. Agregamos un Model, un ViewModel y una clase Helper, e incluso la Vista para representar visualmente la lista. Ahora es tiempo de agregar el pegamento que ata todo junto: El Controller.
El Controller
La aplicación web TODO List que estamos creando solamente servirá para un propósito: ¡Será una lista TODO, lista de cosas por hacer! Por lo tanto, solamente necesitamos un solo controlador, llamado HomeController. En una aplicación más grande, este sería llamado TodoController o TodoListController, pero al llamarlo HomeController, podemos accesar a la vista Index(la cual también será la única vista requerida) desde la raíz de la aplicación web.
Nuestro Controller tiene varias acciones que nos permitirán agregar nuevos elementos a la lista TODO, tambien eliminar y editar los elementos existentes. Todas estas acciones requieren sus propios métodos, los cuales pueden requerir alguna explicación, así que iré por cada método individualmente primero, luego tendrás el código del controlador completo listado al final.
Index():
public IActionResult Index()
{
TodoListViewModel viewModel = new TodoListViewModel();
return View("Index", viewModel);
}
No pasa mucho aquí. Ya que nuestra aplicación de lista TODO solamente tiene una Vista, aquí es donde la entregamos. Ya que la vista usa el TodoListViewModel, creamos una instancia de aquí (la cual carga los elementos TODO, como describimos en el artículo previo) y luego los pasa a la vista usando el método View().
Edit():
public IActionResult Edit(int id)
{
TodoListViewModel viewModel = new TodoListViewModel();
viewModel.EditableItem = viewModel.TodoItems.FirstOrDefault(x => x.Id == id);
return View("Index", viewModel);
}
La acción Edit() funciona como el método Index(), excepto por la linea de la mitad, donde establecemos la propiedad EditableItem para el elemento solicitado por el usuario a través del parámetro id. Reusamos la misma Vista (Index), la cual automáticamente respondera al hecho de que estamos pasando un TodoListItem existente.
Delete():
public IActionResult Delete(int id)
{
using(var db = DbHelper.GetConnection())
{
TodoListItem item = db.Get<TodoListItem>(id);
if(item != null)
db.Delete(item);
return RedirectToAction("Index");
}
}
El método Delete(), tal como el método Edit(), toma un solo parametro llamado id - con ese parámetro, podemos encontrar el elemento solicitado de la base de datos (usando el método Get() desde Dapper.Contrib) y cuando lo tengamos, podemos llamar al método Delete() en el (de nuevo desde Dapper.Contrib). Este es un buen ejemplo de como Dapper y Dapper.Contrib hace todo más fácil para nosotros - en vez de tener que escribir la consulta SQL para traer y luego borrar un registro, simplemente usamos los métodos .NET.
CreateUpdate():
public IActionResult CreateUpdate(TodoListViewModel viewModel)
{
if(ModelState.IsValid)
{
using(var db = DbHelper.GetConnection())
{
if(viewModel.EditableItem.Id <= 0)
{
viewModel.EditableItem.AddDate = DateTime.Now;
db.Insert<TodoListItem>(viewModel.EditableItem);
}
else
{
TodoListItem dbItem = db.Get<TodoListItem>(viewModel.EditableItem.Id);
var result = TryUpdateModelAsync<TodoListItem>(dbItem, "EditableItem");
db.Update<TodoListItem>(dbItem);
}
}
return RedirectToAction("Index");
}
else
return View("Index", new TodoListViewModel());
}
El método mas complejo en nuestro controlador es el método CreateUpdate(). Ya que el FORM que tenemos en nuestra Vista será usado tanto para agregar nuevos elementos como para editar elementos, el método que manejará la solicitud también necesita manejar ambas situaciones.
La primera cosa que hacemos, es checar la propiedad ModelState.IsValid - esta nos dirá sí nuestro Model puede ser validado o no, de acuerdo a la validación del modelo que agregamos en el artículo previo. Sí no es válido, llamamos al método View() y simplemente mostramos la vista Index de nuevo - sin embargo, el ModelState será incluido y será usado en el resumen de validación que mostramos en nuestra Vista, para mostrar los errores de validación generados cuando se validó el Model.
Sí el modelo es válido, miramos la propiedad Id del EditableItem - sí no es mas grande que 0 entonces estamos tratando con un nuevo elemento. Simplemente asignamos el DateTime actual a la propiedad AddDate y luego llamamos al método Insert() para insertar nuestro nuevo elemento en la base de datos.
Sí el Id es más grande que cero, entonces estamos tratando con un elemento existente. Traemos el elemento real de la base de datos y luego llamamos al método TryUpdateModelAsync() sobre este. Esto actualizará el objeto que tememos desde la base de datos con los valores encontrados en el Modelo posteado al servidor, el cual en este caso es básicamente la propiedad Title. Una vez que nuestro modelo ha sido actualizado, escribimos los cambios de vuelta a la base de datos llamando al método Update().
Cuando todo esto esta hecho, simplemente hacemos un redireccionamiento a la acción Index, esencialmente retorna todo de la forma que estaba antes. Los cambios hechos automáticamente serán reflejados cuando la acción Index y el ViewModel sean cargados. Esta atento a que no realizamos ninguna revisión de errores o manejo de excepciones durante este proceso, esto para conservar el ejemplo tan compacto como fuera posible - deberías desde luego, como mínimo, manejar alguna posible excepción en una aplicación del mundo real.
ToggleIsDone:
public IActionResult ToggleIsDone(int id)
{
using(var db = DbHelper.GetConnection())
{
TodoListItem item = db.Get<TodoListItem>(id);
if(item != null)
{
item.IsDone = !item.IsDone;
db.Update<TodoListItem>(item);
}
return RedirectToAction("Index");
}
}
Activamos esta acción con una pequeña pieza de JavaScript encontrado en nuestra Vista. Simplemente traera el TodoListItem especificado por el parámetro id usando el método Get() en la base de datos. Una vez que tengamos el elemento, podemos cambiar la propiedad IsDone a Falso sí esta en Verdadero y viceversa. Tan pronto como hayamos hecho eso, podemos actualizar el registro correspondiente en la base de datos, usando el método Update().
Esa fue el método final en nuestro Controlador. Como prometí, aquí esta listado el código completo:
using System;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using TodoList.Models;
using Dapper;
using Dapper.Contrib.Extensions;
using TodoList.ViewModels;
using TodoList.Helpers;
namespace TodoList.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
TodoListViewModel viewModel = new TodoListViewModel();
return View("Index", viewModel);
}
public IActionResult Edit(int id)
{
TodoListViewModel viewModel = new TodoListViewModel();
viewModel.EditableItem = viewModel.TodoItems.FirstOrDefault(x => x.Id == id);
return View("Index", viewModel);
}
public IActionResult Delete(int id)
{
using(var db = DbHelper.GetConnection())
{
TodoListItem item = db.Get<TodoListItem>(id);
if(item != null)
db.Delete(item);
return RedirectToAction("Index");
}
}
public IActionResult CreateUpdate(TodoListViewModel viewModel)
{
if(ModelState.IsValid)
{
using(var db = DbHelper.GetConnection())
{
if(viewModel.EditableItem.Id <= 0)
{
viewModel.EditableItem.AddDate = DateTime.Now;
db.Insert<TodoListItem>(viewModel.EditableItem);
}
else
{
TodoListItem dbItem = db.Get<TodoListItem>(viewModel.EditableItem.Id);
TryUpdateModelAsync<TodoListItem>(dbItem, "EditableItem");
db.Update<TodoListItem>(dbItem);
}
}
return RedirectToAction("Index");
}
else
return View("Index", new TodoListViewModel());
}
public IActionResult ToggleIsDone(int id)
{
using(var db = DbHelper.GetConnection())
{
TodoListItem item = db.Get<TodoListItem>(id);
if(item != null)
{
item.IsDone = !item.IsDone;
db.Update<TodoListItem>(item);
}
return RedirectToAction("Index");
}
}
}
}
Resumen
¡Felicidades, has construido tu propia aplicación web! Ahora agrega algunos elementos, haz clic en ellos para editarlos, clic en el checkbox para cambiar la propiedad IsDone o da clic en el botón Delete para remover un elemento. Todos los cambios serán reflejados en la base de datos y seran visibles la siguiente vez que cargues la página - ¡genial!