> Manuales > Manual del framework ASP.NET MVC

Los helpers nos van a permitir crear campos para crear un formulario de una manera muy cómoda.

En el artículo anterior vimos el uso de POST en ASP.NET MVC junto con las bases del Model Binding. En concreto la norma más importante que debemos recordad es que el atributo name del campo debe llamarse igual que la propiedad que queremos enlazar. Por supuesto que el Model Binder admite enlazar parámetros complejos (una clase que tenga una propiedad que sea una lista de objetos que a su vez tengan más propiedades simples o complejas) y en este caso basta que los atributos name de los campos del formulario sigan unas determinadas reglas. No vamos a entrar más en detalle porque, por suerte el framework nos ofrece una ayuda para no tener que recordar exactamente todas esas reglas: Los helpers para formularios.

Los helpers nos van a permitir crear campos para crear un formulario de una manera muy cómoda y son sin duda alguna la manera preferida de hacerlo.

Crear campos HTML

Lo primero que vamos a ver es como crear un campo HTML para editar (o mostrar) una propiedad específica del Viewmodel que recibe la vista. Supongamos que tenemos esa clase:

public class Trabajador
{
public string Nombre { get; set; }
public string Apellido { get; set; }
public DateTime FechaNacimiento { get; set; }
public double Sueldo { get; set; }
public bool EsFijo { get; set; }
}

Ahora vamos a crear una vista que muestre cuatro campos de texto (para nombre, apellido, fecha de nacimiento y sueldo) y una casilla de verificación para indicar si es fijo o no. Pero en lugar de crear los controles a mano (<input type="xxx">) vamos a usar los helpers:

@using MvchelpersForms.Models
@model Trabajador

<form method="post">

Nombre: @Html.TextBoxFor(x=>x.Nombre) <br />
Apellido: @Html.TextBoxFor(x=>x.Apellido) <br />
Fecha Nacimiento: @Html.TextBoxFor(x=>x.FechaNacimiento) <br />
Sueldo: @Html.TextBoxFor(x => x.Sueldo) <br />
Es Fijo: @Html.CheckBoxFor(x=>x.EsFijo) <br />

<input type="submit" value="Enviar"/>

</form>

Estamos usando los helpers:

Fijaos en como se indica a cada helper para que propiedad debe renderizar el control:

@Html.TextBoxFor(x=>x.Nombre)

El parámetro en forma x=>x.Nombre es una expresión lambda. No es objetivo de este artículo entrar en las expresiones lambda, así que nos vamos a limitar a indicar que en este caso se usan para indicar la propiedad. La ventaja de usar una expresión lambda antes que una cadena (algo como TextBoxFor("Nombre")) es que las expresiones lambda son evaluadas en tiempo de compilación y no de ejecución (si nos equivocamos en el nombre de la propiedad el código no compila). Esto requiere que la vista sea tipada con el tipo de ViewModel (fijaos en el uso de la directiva @model).

Bien, ahora veamos que código fuente nos ha generado esta vista:

<form method="post">

Nombre: <input id="Nombre" name="Nombre" type="text" value="" /> <br />
Apellido: <input id="Apellido" name="Apellido" type="text" value="" /> <br />
Fecha Nacimiento: <input id="FechaNacimiento" name="FechaNacimiento" type="text" value="" /> <br />
Sueldo: <input id="Sueldo" name="Sueldo" type="text" value="" /> <br />
Es Fijo: <input id="EsFijo" name="EsFijo" type="checkbox" value="true" /><input name="EsFijo" type="hidden" value="false" /> <br />

<input type="submit" value="Enviar"/>

</form>

La verdad es que no se diferencia mucho del código que nosotros pondríamos a mano (que vimos en el artículo anterior). Lo que sí os puede llamar la curiosidad es el campo hidden cuyo name es "EsFijo". Este campo existe para… bueno, para lidiar con el hecho de que una checkbox no marcada, no se envía. Es decir si tenemos el campo:

<input id="EsFijo" name="EsFijo" type="checkbox" value="true" />

Eso significa que si la checkbox está marcada se enviará el valor indicado en value (true), mientras que si la checkbox no está marcada el navegador no enviará nada. Una checkbox no marcada es como si no existiese. Pero el Model Binder de ASP.NET MVC esperará que haya un campo EsFijo para poder enlazarlo a la propiedad, de ahí que se añada este campo hidden con el mismo nombre y valor false. De este modo si la checkbox no está marcada el campo hidden se envía y tiene el valor de false. ¿Habrías pensado tú en eso? Esas son las ventajas de usar los helpers :)

Ventajas de usar los helpers

Pero todavía hay más, si mostráis la vista en el navegador y sin introducir datos le dais a Enviar:

¡Exacto! Nos aparecen errores. En concreto el sistema nos muestra un error si FechaNacimiento o Sueldo están vacíos. ¿Y por qué esos dos campos y no los otros? Muy sencillo: porque esos dos campos están declarados como DateTime y double que son tipos por valor y por lo tanto nunca pueden valer null.

Ahora… probad de meter una cadena en el Sueldo:

¡Sigue dando error! Esto es porque la cadena “dsddsd” no puede ser convertida en double, lo que genera un error.

Ahora bien, quiero dejar una cosa bien clara: El sistema siempre realiza esas validaciones con independencia de que usemos los helpers o no. Pero estos últimos están preparados para mostrar el error (usar una clase CSS específica) si ese existe.

Ahora igual os surge la siguiente duda: ¿Y si no uso los helpers como puedo saber si hay errores en un campo concreto? Pues haciendo lo mismo que realmente hacen ellos: Acceder a la propiedad ModelState del ViewData que entre otras cosas contiene los errores vinculados a una propiedad. Mirad como sería el código si queremos generar el campo Sueldo para que se comporte igual que usando el helper:

<input type="text" name="Sueldo" value="@(Model != null ? Model.Sueldo.ToString() : string.Empty)"
class="@(ViewData.ModelState.ContainsKey("Sueldo") && ViewData.ModelState["Sueldo"].Errors.Any() ? "input-validation-error" : string.Empty )"
/>

Tenemos que realizar manualmente las dos tareas que el helper hace por nosotros:

Así pues, los helpers no son imprescindibles. Pero sí que son muy cómodos y la manera recomendable de construir formularios en ASP.NET MVC.

Hemos visto TextBoxFor y CheckBoxFor pero hay un helper por cada control HTML que habitualmente usamos en formularios, así tenemos Html.TextAreaFor, Html.LabelFor, Html.DropDownListFor, etc…

Os muestro el uso de Html.LabelFor porque es otro que se usa muchísimo. Ese genera un campo

@Html.LabelFor(x=>x.Nombre) @Html.TextBoxFor(x=>x.Nombre) <br />

Nos genera el código HTML:

<label for="Nombre">Nombre</label> <input id="Nombre" name="Nombre" type="text" value="" /> <br />

La etiqueta <label> se renderiza como texto plano. La ventaja de usarla es que al pulsar sobre la label el navegador da el foco al control indicado en el atributo for (en ese caso el textbox de al lado).

Personalización de los helpers

¿Si a un helper sólo le puedo pasar una expresión lambda que indica la propiedad para la cual debe renderizar un determinado control HTML, como puedo personalizarlos? Por personalizarlos me refiero a poder añadir atributos HTML adicionales como style o cualquier otro.

Pues bien, muchos de los helpers tienen una sobrecarga donde admiten un objeto anónimo cuyas propiedades serán mapeadas a atributos HTML al generar el código. Así pues el siguiente código en la vista:

@Html.LabelFor(x => x.Nombre) @Html.TextBoxFor(x => x.Nombre, new { style = "border-color: blue", size = "30" })

Genera el siguiente código HTML:

<input id="Nombre" name="Nombre" size="30" style="border-color: blue" type="text" value="" />

Helpers "inteligentes"

Con los helpers que hemos visto hasta ahora es nuestra responsabilidad la de decidir qué control HTML mapeamos a cada propiedad (un textbox, una checkbox, etc). Pero ASP.NET MVC incorpora dos helpers, llamémosles "inteligentes" que son capaces de determinar cuál es el mejor control para visualizar o editar una propiedad concreta.

Esos dos helpers son:

Esos helpers son extraordinariamente potentes (tanto que van a tener un artículo para ellos solos) así que por ahora vamos a ver solo su uso:

@using MvcHelpersForms.Models
@model Trabajador
<form method="post">
@Html.LabelFor(x => x.Nombre) @Html.EditorFor(x => x.Nombre)
<br />
Apellido: @Html.EditorFor(x => x.Apellido)
<br />
Fecha Nacimiento: @Html.EditorFor(x => x.FechaNacimiento)
<br />
Sueldo: @Html.EditorFor(x => x.Sueldo) <br />
Es Fijo: @Html.EditorFor(x => x.EsFijo)
<br />
<input type="submit" value="Enviar" />
</form>

Fijaos que ahora usamos solamente Html.EditorFor. El código HTML generado ahora es:

<form method="post">
<label for="Nombre">Nombre</label> <input class="text-box single-line" id="Nombre" name="Nombre" type="text" value="" />
<br />
Apellido: <input class="text-box single-line" id="Apellido" name="Apellido" type="text" value="" />
<br />
Fecha Nacimiento: <input class="text-box single-line" id="FechaNacimiento" name="FechaNacimiento" type="text" value="" />
<br />
Sueldo: <input class="text-box single-line" id="Sueldo" name="Sueldo" type="text" value="" /> <br />
Es Fijo: <input class="check-box" id="EsFijo" name="EsFijo" type="checkbox" value="true" /><input name="EsFijo" type="hidden" value="false" />
<br />
<input type="submit" value="Enviar" />
</form>

Este código es casi idéntico al que teníamos antes. Html.EditorFor renderiza un cuadro de texto para cada propiedad a excepción de la booleana para la cual renderiza una casilla de verificación.

La pregunta evidente es: ¿Si existe EditorFor para que usar el resto de helpers? Pues bien, cuando queráis vosotros decidir cuál es el control HTML se usa para visualizar o mostrar una propiedad podéis usar los helpers que vimos antes. Cuando queráis que sea el sistema usad EditorFor (o DisplayFor si estáis realizando una vista que no permita editar). Como ya os he avanzado antes EditorFor y DisplayFor son extraordinariamente potentes y con ellos se pueden hacer auténticas maravillas, pero eso lo veremos en un artículo próximo.

El helper BeginForm

Bueno, ya que hablamos de helpers para generar formularios este es un buen momento para introducir el helper BeginForm. Este helper lo que genera es… el tag <form>. Bueno, de hecho el tag <form> y su parejo </form>. Es por ello que ese helper se "usa" de una forma un poco… distinta:

@using (Html.BeginForm()) {
<!-- Codigo del formulario -->
}

El código que genera el formulario se incluye dentro de las llaves de apertura y cierre. Cuando se encuentre la llave de cierra se generará el tag </form>. Al usar BeginForm() debemos tener un poco más de cuidado con Razor. El siguiente código da error:

@Html.LabelFor(x => x.Nombre) @Html.EditorFor(x => x.Nombre)
<br />
Apellido: @Html.EditorFor(x => x.Apellido)
<br />
Fecha Nacimiento: @Html.EditorFor(x => x.FechaNacimiento)
<br />
Sueldo: @Html.EditorFor(x => x.Sueldo) <br />
Es Fijo: @Html.EditorFor(x => x.EsFijo)
<br />
<input type="submit" value="Enviar" />
}

La razón es que Razor interpreta que debe ejecutar el código que se encuentra entre las llaves. Por supuesto, como ya vimos, Razor es lo suficientemente inteligente para "ignorar" el código HTML (como <br />) pero no el texto plano. Es decir, Razor intentará ejecutar el código Apellido: (o Es Fijo:) que un código totalmente inválido en C#, de ahí el error.

¿La solución? La que vimos en el artículo que dedicamos a Razor, o bien usamos @: o bien usamos la etiqueta ficticia <text> para indicarle a Razor que este texto plano es eso… texto plano, que debe mandar a la salida HTML sin más:

@using (Html.BeginForm()) {
@Html.LabelFor(x => x.Nombre) @Html.EditorFor(x => x.Nombre)
<br />
@:Apellido: @Html.EditorFor(x => x.Apellido)
<br />
@:Fecha Nacimiento: @Html.EditorFor(x => x.FechaNacimiento)
<br />
<text>Sueldo:</text> @Html.EditorFor(x => x.Sueldo) <br />
<text>Es Fijo:</text> @Html.EditorFor(x => x.EsFijo)
<br />
<input type="submit" value="Enviar" />
}

¡Bueno! Suficiente por hoy, ¿no? En este artículo hemos visto que son los helpers para formulario, como se usan y cuáles son sus ventajas. En el siguiente artículo vamos a hablar de un tema importantísimo: las validaciones

Eduard Tomàs

Apasionado de la informática, los videojuegos, rol y... la cerveza. Key Consulta...

Manual