Asistentes de etiquetas en formularios de ASP.NET Core
Por Rick Anderson, N. Taylor Mullen, Dave Paquette y Jerrie Pelser
En este documento se explica cómo trabajar con formularios y se detallan los elementos HTML que se usan habitualmente en un formulario. El elemento HTML Form proporciona el mecanismo principal que las aplicaciones web usan a la hora de devolver datos al servidor. La mayor parte de este documento se centra en describir los asistentes de etiquetas y cómo pueden servir para crear formularios HTML eficaces de manera productiva. Se recomienda leer Introduction to Tag Helpers (Introducción a los asistentes de etiquetas) antes de este documento.
En muchos casos, los asistentes de HTML proporcionan un método alternativo para un asistente de etiquetas específico, pero es importante tener en cuenta que los asistentes de etiquetas no reemplazan a los asistentes de HTML y que no hay un asistente de etiquetas para cada asistente de HTML. Si existe una alternativa del asistente de HTML, se mencionará aquí.
Asistente de etiquetas de formulario (Form)
El asistente de etiquetas Form hace lo siguiente:
Genera el valor del atributo <FORM>
action
HTML para una acción del controlador MVC o una ruta con nombreGenera un token comprobación de solicitudes oculto que impide que se falsifiquen solicitudes entre sitios (cuando se usa con el atributo
[ValidateAntiForgeryToken]
en el método de acción HTTP Post).Proporciona el atributo
asp-route-<Parameter Name>
, donde<Parameter Name>
se agrega a los valores de ruta. Los parámetrosrouteValues
deHtml.BeginForm
yHtml.BeginRouteForm
proporcionan una funcionalidad similar.Tiene
Html.BeginForm
yHtml.BeginRouteForm
como alternativa del asistente de HTML.
Sample:
<form asp-controller="Demo" asp-action="Register" method="post">
<!-- Input and Submit elements -->
</form>
El asistente de etiquetas Form anterior genera el siguiente HTML:
<form method="post" action="/Demo/Register">
<!-- Input and Submit elements -->
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
El tiempo de ejecución MVC genera el valor de atributo action
de los atributos del asistente de etiquetas Form asp-controller
y asp-action
. El asistente de etiquetas Form genera también un token de comprobación de solicitudes oculto que impide que se falsifiquen solicitudes entre sitios (cuando se usa con el atributo [ValidateAntiForgeryToken]
en el método de acción HTTP Post). Proteger un elemento HTML Form puro de la falsificación de solicitudes entre sitios no es tarea fácil, y el asistente de etiquetas Form presta este servicio.
Uso de una ruta con nombre
El atributo del asistente de etiquetas asp-route
puede generar también el marcado del atributo HTML action
. Una aplicación con una ruta denominada register
podría utilizar el siguiente marcado para la página de registro:
<form asp-route="register" method="post">
<!-- Input and Submit elements -->
</form>
Muchas de las vistas de la carpeta Views/Account (que se genera cuando se crea una aplicación web con Cuentas de usuario individuales) contienen el atributoasp-route-returnurl:
<form asp-controller="Account" asp-action="Login"
asp-route-returnurl="@ViewData["ReturnUrl"]"
method="post" class="form-horizontal" role="form">
Nota
Con las plantillas integradas, returnUrl
se rellena automáticamente solo cuando alguien intenta obtener acceso a un recurso autorizado, pero no se ha autenticado o no tiene autorización. Si se intenta realizar un acceso no autorizado, el middleware de seguridad redirige a la página de inicio de sesión con returnUrl
configurado.
Asistente de etiquetas de acción de formulario
El asistente de etiquetas de acción de formulario genera el atributo formaction
en la etiqueta <button ...>
o <input type="image" ...>
generadas. El atributo formaction
controla el lugar donde un formulario envía sus datos. Se vincula a los elementos <input> de tipo image
y <button>. El asistente de etiquetas de acción de formulario permite el uso de varios atributos AnchorTagHelper asp-
para controlar qué vínculo formaction
se genera para el elemento correspondiente.
Atributos AnchorTagHelper admitidos para controlar el valor de formaction
:
Atributo | Descripción |
---|---|
asp-controller | El nombre del controlador. |
asp-action | El nombre del método de acción. |
asp-area | El nombre del área. |
asp-page | El nombre de la página Razor. |
asp-page-handler | El nombre del controlador de la página Razor. |
asp-route | Nombre de la ruta. |
asp-route-{value} | Un valor único de ruta de dirección URL. Por ejemplo: asp-route-id="1234" . |
asp-all-route-data | Todos los valores de ruta. |
asp-fragment | El fragmento de dirección URL. |
Ejemplo de envío al controlador
El marcado siguiente envía el formulario a la acción Index
de HomeController
cuando se selecciona el elemento input o button:
<form method="post">
<button asp-controller="Home" asp-action="Index">Click Me</button>
<input type="image" src="..." alt="Or Click Me" asp-controller="Home"
asp-action="Index">
</form>
El marcado anterior genera el siguiente código HTML:
<form method="post">
<button formaction="/Home">Click Me</button>
<input type="image" src="..." alt="Or Click Me" formaction="/Home">
</form>
Ejemplo de envío a la página
El siguiente código envía el formulario a la página About
Razor Page:
<form method="post">
<button asp-page="About">Click Me</button>
<input type="image" src="..." alt="Or Click Me" asp-page="About">
</form>
El marcado anterior genera el siguiente código HTML:
<form method="post">
<button formaction="/About">Click Me</button>
<input type="image" src="..." alt="Or Click Me" formaction="/About">
</form>
Ejemplo de envío a la ruta
Tenga en cuenta el punto de conexión /Home/Test
:
public class HomeController : Controller
{
[Route("/Home/Test", Name = "Custom")]
public string Test()
{
return "This is the test page";
}
}
El marcado siguiente envía el formulario al punto de conexión /Home/Test
.
<form method="post">
<button asp-route="Custom">Click Me</button>
<input type="image" src="..." alt="Or Click Me" asp-route="Custom">
</form>
El marcado anterior genera el siguiente código HTML:
<form method="post">
<button formaction="/Home/Test">Click Me</button>
<input type="image" src="..." alt="Or Click Me" formaction="/Home/Test">
</form>
Asistente de etiquetas de entrada (Input)
El asistente de etiqueta de entrada vincula un elemento HTML de <entrada> a una expresión de modelo en tu vista razor.
Sintaxis:
<input asp-for="<Expression Name>">
El asistente de etiquetas Input hace lo siguiente:
Genera los atributos HTML y del nombre de expresión especificado en el atributo.
asp-for="Property1.Property2"
equivale am => m.Property1.Property2
. El nombre de una expresión es lo que se usa para el valor de atributoasp-for
. Vea la sección Nombres de expresión para obtener más información.Establece el valor del atributo HTML
type
basándose en el tipo de modelo y los atributos data annotation aplicados a la propiedad del modeloNo sobrescribirá el valor de atributo HTML
type
cuando se especifique uno.Genera atributos de validación HTML5 a partir de atributos data annotation aplicados a las propiedades del modelo
Tiene características del asistente de HTML que se superponen a
Html.TextBoxFor
yHtml.EditorFor
. Vea la sección Alternativas del asistente de HTML al asistente de etiquetas Input para obtener más información.Permite establecer tipado fuerte. Si el nombre de la propiedad cambia y no se actualiza el asistente de etiquetas, aparecerá un error similar al siguiente:
An error occurred during the compilation of a resource required to process this request. Please review the following specific error details and modify your source code appropriately. Type expected 'RegisterViewModel' does not contain a definition for 'Email' and no extension method 'Email' accepting a first argument of type 'RegisterViewModel' could be found (are you missing a using directive or an assembly reference?)
El asistente de etiquetas Input
establece el atributo HTML type
en función del tipo .NET. En la siguiente tabla se enumeran algunos tipos .NET habituales y el tipo HTML generado correspondiente (no incluimos aquí todos los tipos .NET).
Tipo de .NET | Tipo de entrada |
---|---|
Bool | type="checkbox" |
String | type="text" |
DateTime | type="datetime-local" |
Byte | type="number" |
Int | type="number" |
Single, Double | type="number" |
En la siguiente tabla se muestran algunos atributos de anotación de datos comunes que el asistente de etiquetas Input asignará a tipos de entrada concretos (no incluimos aquí todos los atributo de validación):
Atributo | Tipo de entrada |
---|---|
[EmailAddress] | type="email" |
[Url] | type="url" |
[HiddenInput] | type="hidden" |
[Phone] | type="tel" |
[DataType(DataType.Password)] | type="password" |
[DataType(DataType.Date)] | type="date" |
[DataType(DataType.Time)] | type="time" |
Sample:
using System.ComponentModel.DataAnnotations;
namespace FormsTagHelper.ViewModels
{
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
}
}
@model RegisterViewModel
<form asp-controller="Demo" asp-action="RegisterInput" method="post">
<label>Email: <input asp-for="Email" /></label> <br />
<label>Password: <input asp-for="Password" /></label><br />
<button type="submit">Register</button>
</form>
El código anterior genera el siguiente HTML:
<form method="post" action="/Demo/RegisterInput">
Email:
<input type="email" data-val="true"
data-val-email="The Email Address field is not a valid email address."
data-val-required="The Email Address field is required."
id="Email" name="Email" value=""><br>
Password:
<input type="password" data-val="true"
data-val-required="The Password field is required."
id="Password" name="Password"><br>
<button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Las anotaciones de datos que se aplican a las propiedades Email
y Password
generan metadatos en el modelo. El asistente de etiquetas de entrada usa esos metadatos del modelo y genera atributos HTML5 data-val-*
(consulte Validación del modelo). Estos atributos describen los validadores que se van a adjuntar a los campos de entrada, lo que proporciona HTML5 discreto y validación de jQuery. Los atributos discretos tienen el formato data-val-rule="Error Message"
, donde rule es el nombre de la regla de validación (como data-val-required
, data-val-email
, data-val-maxlength
, etc.) Si se proporciona un mensaje de error en el atributo, se muestra como valor para el atributo data-val-rule
. También hay atributos con el formato data-val-ruleName-argumentName="argumentValue"
que aportan más información sobre la regla, por ejemplo, data-val-maxlength-max="1024"
.
Cuando se vinculan varios controles input
a la misma propiedad, los controles generados comparten el mismo id
, lo que hace que el marcado generado no sea válido. Para evitar duplicados, especifique explícitamente el atributo id
para cada control.
Renderizado de entradas ocultas de casillas de verificación
Las casillas de verificación en HTML5 no envían un valor cuando están desmarcadas. Para permitir que se envíe un valor predeterminado para una casilla de verificación sin marcar, el asistente de etiquetas de entrada genera una entrada oculta adicional para las casillas de verificación.
Por ejemplo, considere el siguiente marcado Razor que utiliza el asistente de etiqueta de entrada para una propiedad de modelo booleano IsChecked
:
<form method="post">
<input asp-for="@Model.IsChecked" />
<button type="submit">Submit</button>
</form>
La marca Razor anterior genera una marca HTML similar a la siguiente:
<form method="post">
<input name="IsChecked" type="checkbox" value="true" />
<button type="submit">Submit</button>
<input name="IsChecked" type="hidden" value="false" />
</form>
El marcado HTML anterior muestra una entrada oculta adicional con un nombre de IsChecked
y un valor de false
. De manera predeterminada, esta entrada oculta se muestra al final del formulario. Cuando se envía el formulario:
- Si la casilla
IsChecked
está marcada, tantotrue
comofalse
son enviados como valores. - Si la casilla de verificación
IsChecked
no está marcada, solo se envía el valor ocultofalse
.
El proceso de vinculación de modelos de ASP.NET Core solo lee el primer valor cuando se vincula a un valor bool
, lo que da como resultado true
para casillas de verificación marcadas y false
para casillas de verificación sin marcar.
Para configurar el comportamiento de la representación de la entrada oculta, establezca la propiedad CheckBoxHiddenInputRenderMode en MvcViewOptions.HtmlHelperOptions. Por ejemplo:
services.Configure<MvcViewOptions>(options =>
options.HtmlHelperOptions.CheckBoxHiddenInputRenderMode =
CheckBoxHiddenInputRenderMode.None);
El código anterior desactiva la representación de la entrada oculta para las casillas de verificación estableciendo CheckBoxHiddenInputRenderMode
en CheckBoxHiddenInputRenderMode.None. Para todos los modos de representación disponibles, vea el enum CheckBoxHiddenInputRenderMode.
Alternativas del asistente de HTML al asistente de etiquetas Input
Html.TextBox
, Html.TextBoxFor
, Html.Editor
y Html.EditorFor
tienen características que se superponen al asistente de etiquetas Input. El asistente de etiquetas Input establecerá automáticamente el atributo type
, cosa que no ocurrirá con Html.TextBox
ni Html.TextBoxFor
. Html.Editor
y Html.EditorFor
controlan colecciones, objetos complejos y plantillas, pero el asistente de etiquetas Input no. El Input Tag Helper, Html.EditorFor
y Html.TextBoxFor
están fuertemente tipados (utilizan expresiones lambda); Html.TextBox
y Html.Editor
no lo están (utilizan nombres de expresiones).
HtmlAttributes
@Html.Editor()
y @Html.EditorFor()
usan una entrada ViewDataDictionary
especial denominada htmlAttributes
al ejecutar sus plantillas predeterminadas. Si lo desea, este comportamiento se puede enriquecer con parámetros additionalViewData
. En la clave "htmlAttributes" se distingue entre mayúsculas y minúsculas. La clave "htmlAttributes" se controla de forma similar al objeto htmlAttributes
pasado a asistentes de etiquetas Input como @Html.TextBox()
.
@Html.EditorFor(model => model.YourProperty,
new { htmlAttributes = new { @class="myCssClass", style="Width:100px" } })
Nombres de expresión
El valor del atributo asp-for
es una ModelExpression
y la parte de la derecha de una expresión lambda. Por tanto, asp-for="Property1"
se convierte en m => m.Property1
en el código generado, motivo por el que no es necesario incluir el prefijo Model
. Puede usar el carácter "@" para iniciar una expresión insertada y moverla antes de m.
:
@{
var joe = "Joe";
}
<input asp-for="@joe">
Se genera el siguiente HTML:
<input type="text" id="joe" name="joe" value="Joe">
Con las propiedades de colección, asp-for="CollectionProperty[23].Member"
genera el mismo nombre que asp-for="CollectionProperty[i].Member"
si i
tiene el valor 23
.
Cuando ASP.NET Core MVC calcula el valor de ModelExpression
, inspecciona varios orígenes, ModelState
incluido. Fíjese en <input type="text" asp-for="Name">
. El atributo value
calculado es el primer valor distinto de null de:
- La entrada
ModelState
con la clave "Name". - El resultado de la expresión
Model.Name
.
Navegar a las propiedades secundarias
También se puede navegar a las propiedades secundarias a través de la ruta de acceso de propiedades del modelo de vista. Pensemos en una clase de modelo más compleja que contiene una propiedad secundaria Address
.
public class AddressViewModel
{
public string AddressLine1 { get; set; }
}
public class RegisterAddressViewModel
{
public string Email { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
public AddressViewModel Address { get; set; }
}
En la vista, enlazamos a Address.AddressLine1
:
@model RegisterAddressViewModel
<form asp-controller="Demo" asp-action="RegisterAddress" method="post">
<label>Email: <input asp-for="Email" /></label> <br />
<label>Password: <input asp-for="Password" /></label><br />
<label>Address: <input asp-for="Address.AddressLine1" /></label><br />
<button type="submit">Register</button>
</form>
Se genera el siguiente código HTML para Address.AddressLine1
:
<input type="text" id="Address_AddressLine1" name="Address.AddressLine1" value="">
Colecciones y nombres de expresión
Como ejemplo, un modelo que contiene una matriz de Colors
:
public class Person
{
public List<string> Colors { get; set; }
public int Age { get; set; }
}
El método de acción:
public IActionResult Edit(int id, int colorIndex)
{
ViewData["Index"] = colorIndex;
return View(GetPerson(id));
}
La siguiente Razor muestra cómo se accede a un elemento Color
específico:
@model Person
@{
var index = (int)ViewData["index"];
}
<form asp-controller="ToDo" asp-action="Edit" method="post">
@Html.EditorFor(m => m.Colors[index])
<label asp-for="Age"></label>
<input asp-for="Age" /><br />
<button type="submit">Post</button>
</form>
La plantilla Views/Shared/EditorTemplates/String.cshtml
:
@model string
<label asp-for="@Model"></label>
<input asp-for="@Model" /> <br />
Ejemplo en el que se usa List<T>
:
public class ToDoItem
{
public string Name { get; set; }
public bool IsDone { get; set; }
}
La siguiente Razor muestra cómo iterar sobre una colección:
@model List<ToDoItem>
<form asp-controller="ToDo" asp-action="Edit" method="post">
<table>
<tr> <th>Name</th> <th>Is Done</th> </tr>
@for (int i = 0; i < Model.Count; i++)
{
<tr>
@Html.EditorFor(model => model[i])
</tr>
}
</table>
<button type="submit">Save</button>
</form>
La plantilla Views/Shared/EditorTemplates/ToDoItem.cshtml
:
@model ToDoItem
<td>
<label asp-for="@Model.Name"></label>
@Html.DisplayFor(model => model.Name)
</td>
<td>
<input asp-for="@Model.IsDone" />
</td>
@*
This template replaces the following Razor which evaluates the indexer three times.
<td>
<label asp-for="@Model[i].Name"></label>
@Html.DisplayFor(model => model[i].Name)
</td>
<td>
<input asp-for="@Model[i].IsDone" />
</td>
*@
Si es posible, debe usarse foreach
si el valor se va a utilizar en un contexto equivalente a asp-for
o Html.DisplayFor
. En general, for
es mejor que foreach
(si el escenario lo permite), ya que no necesita asignar ningún enumerador; sin embargo, la evaluación de un indizador en una expresión LINQ puede resultar caro y, por tanto, se debe minimizar.
Nota:
El código de ejemplo comentado anterior muestra cómo reemplazaríamos la expresión lambda por el operador @
para tener acceso a cada elemento ToDoItem
de la lista.
Asistente de etiquetas de área de texto (Textarea)
El asistente de etiquetas Textarea Tag Helper
es similar al asistente de etiquetas de entrada.
Genera los atributos
id
yname
, y los atributos de validación de datos del modelo para un elemento <textarea>.Permite establecer tipado fuerte.
Alternativa del asistente de HTML:
Html.TextAreaFor
Sample:
using System.ComponentModel.DataAnnotations;
namespace FormsTagHelper.ViewModels
{
public class DescriptionViewModel
{
[MinLength(5)]
[MaxLength(1024)]
public string Description { get; set; }
}
}
@model DescriptionViewModel
<form asp-controller="Demo" asp-action="RegisterTextArea" method="post">
<textarea asp-for="Description"></textarea>
<button type="submit">Test</button>
</form>
Se genera el siguiente código HTML:
<form method="post" action="/Demo/RegisterTextArea">
<textarea data-val="true"
data-val-maxlength="The field Description must be a string or array type with a maximum length of '1024'."
data-val-maxlength-max="1024"
data-val-minlength="The field Description must be a string or array type with a minimum length of '5'."
data-val-minlength-min="5"
id="Description" name="Description">
</textarea>
<button type="submit">Test</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Asistente de etiquetas Label
Genera el título de la etiqueta y el atributo
for
en un elemento <etiqueta> para un nombre de expresión.Alternativa del asistente de HTML:
Html.LabelFor
.
El Label Tag Helper
proporciona las siguientes ventajas sobre un elemento label HTML puro:
Obtendrá automáticamente el valor de la etiqueta descriptiva del atributo
Display
. El nombre para mostrar que se busca puede cambiar con el tiempo y la combinación del atributoDisplay
, y el asistente de etiquetas Label aplicará el elementoDisplay
en cualquier lugar donde se use.El código fuente contiene menos marcado.
Permite establecer tipado fuerte con la propiedad de modelo.
Sample:
using System.ComponentModel.DataAnnotations;
namespace FormsTagHelper.ViewModels
{
public class SimpleViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email Address")]
public string Email { get; set; }
}
}
@model SimpleViewModel
<form asp-controller="Demo" asp-action="RegisterLabel" method="post">
<label asp-for="Email"></label>
<input asp-for="Email" /> <br />
</form>
Se genera el siguiente código HTML para el elemento <label>
:
<label for="Email">Email Address</label>
El asistente de etiquetas Label genera el valor de atributo for
de "Email", que es el identificador asociado al elemento <input>
. Los asistentes de etiquetas generan elementos id
y for
coherentes para que se puedan asociar correctamente. El título de este ejemplo proviene del atributo Display
. Si el modelo no contuviera un atributo Display
, el título sería el nombre de propiedad de la expresión. Para invalidar el título predeterminado, añada un título dentro de la etiqueta label.
Asistentes de etiquetas de validación
Hay dos asistentes de etiquetas de validación. Validation Message Tag Helper
(que muestra un mensaje de validación relativo a una única propiedad del modelo) y Validation Summary Tag Helper
(que muestra un resumen de los errores de validación). Input Tag Helper
agrega atributos de validación del lado cliente HTML5 a los elementos de entrada en función de los atributos de anotación de datos de las clases del modelo. La validación también se realiza en el lado servidor. El asistente de etiquetas de validación muestra estos mensajes de error cuando se produce un error de validación.
Asistente de etiquetas de mensaje de validación
Agrega el atributo HTML5
data-valmsg-for="property"
al elemento span, que adjunta los mensajes de error de validación en el campo de entrada de la propiedad de modelo especificada. Cuando se produce un error de validación en el lado cliente, jQuery muestra el mensaje de error en el elemento<span>
.La validación también tiene lugar en el lado servidor. Puede que JavaScript esté deshabilitado en los clientes, mientras que hay algunas validaciones que solo se pueden realizar en el lado servidor.
Alternativa del asistente de HTML:
Html.ValidationMessageFor
El Validation Message Tag Helper
se utiliza con el atributo asp-validation-for
en un elemento HTML span.
<span asp-validation-for="Email"></span>
El asistente de etiquetas de mensaje de validación generará el siguiente código HTML:
<span class="field-validation-valid"
data-valmsg-for="Email"
data-valmsg-replace="true"></span>
Generalmente se utiliza el Validation Message Tag Helper
después de un Input
asistente de etiqueta para la misma propiedad. Gracias a esto, se mostrarán todos los mensajes de error de validación cerca de la entrada que produjo el error.
Nota:
Debe tener una vista con las referencias de script de JavaScript y de jQuery adecuadas para la validación del lado cliente. Para más información, vea Introduction to model validation in ASP.NET Core MVC (Introducción a la validación de modelos en ASP.NET Core MVC).
Cuando se produce un error de validación del lado servidor (por ejemplo, porque haya una validación del lado servidor personalizada o porque la validación del lado cliente esté deshabilitada), MVC pone ese mensaje de error como cuerpo del elemento <span>
.
<span class="field-validation-error" data-valmsg-for="Email"
data-valmsg-replace="true">
The Email Address field is required.
</span>
Asistente de etiquetas de resumen de validación
Tiene como destino todos los elementos
<div>
con el atributoasp-validation-summary
.Alternativa del asistente de HTML:
@Html.ValidationSummary
El Validation Summary Tag Helper
se utiliza para mostrar un resumen de los mensajes de validación. El valor de atributo asp-validation-summary
puede ser cualquiera de los siguientes:
asp-validation-summary | Mensajes de validación que se muestran |
---|---|
All |
Nivel de modelo y de propiedad |
ModelOnly |
Modelo |
None |
None |
Muestra
En el siguiente ejemplo, el modelo de datos tiene atributos DataAnnotation
, lo que genera mensajes de error de validación sobre el elemento <input>
. Cuando se produce un error de validación, el asistente de etiquetas de validación muestra el mensaje de error:
using System.ComponentModel.DataAnnotations;
namespace FormsTagHelper.ViewModels
{
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email Address")]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
}
}
@model RegisterViewModel
<form asp-controller="Demo" asp-action="RegisterValidation" method="post">
<div asp-validation-summary="ModelOnly"></div>
<label>Email: <input asp-for="Email" /></label> <br />
<span asp-validation-for="Email"></span><br />
<label>Password: <input asp-for="Password" /></label><br />
<span asp-validation-for="Password"></span><br />
<button type="submit">Register</button>
</form>
El código HTML generado (cuando el modelo es válido) es este:
<form action="/DemoReg/Register" method="post">
<label>Email: <input name="Email" id="Email" type="email" value=""
data-val-required="The Email field is required."
data-val-email="The Email field is not a valid email address."
data-val="true"></label><br>
<span class="field-validation-valid" data-valmsg-replace="true"
data-valmsg-for="Email"></span><br>
<label>Password: <input name="Password" id="Password" type="password"
data-val-required="The Password field is required." data-val="true"></label><br>
<span class="field-validation-valid" data-valmsg-replace="true"
data-valmsg-for="Password"></span><br>
<button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Asistente de etiquetas de selección (Select)
Genera el elemento select y el elemento asociado option de las propiedades del modelo.
Tiene
Html.DropDownListFor
yHtml.ListBoxFor
como alternativa del asistente de HTML.
Select Tag Helper
asp-for
especifica el nombre de la propiedad de modelo del elemento select, mientras que asp-items
especifica los elementos option. Por ejemplo:
<select asp-for="Country" asp-items="Model.Countries"></select>
Sample:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace FormsTagHelper.ViewModels
{
public class CountryViewModel
{
public string Country { get; set; }
public List<SelectListItem> Countries { get; } = new List<SelectListItem>
{
new SelectListItem { Value = "MX", Text = "Mexico" },
new SelectListItem { Value = "CA", Text = "Canada" },
new SelectListItem { Value = "US", Text = "USA" },
};
}
}
El método Index
inicializa CountryViewModel
, establece el país seleccionado y lo pasa a la vista Index
.
public IActionResult Index()
{
var model = new CountryViewModel();
model.Country = "CA";
return View(model);
}
El método HTTP POST Index
muestra la selección:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(CountryViewModel model)
{
if (ModelState.IsValid)
{
var msg = model.Country + " selected";
return RedirectToAction("IndexSuccess", new { message = msg });
}
// If we got this far, something failed; redisplay form.
return View(model);
}
La vista Index
:
@model CountryViewModel
<form asp-controller="Home" asp-action="Index" method="post">
<select asp-for="Country" asp-items="Model.Countries"></select>
<br /><button type="submit">Register</button>
</form>
Genera el siguiente código HTML (con la selección "CA"):
<form method="post" action="/">
<select id="Country" name="Country">
<option value="MX">Mexico</option>
<option selected="selected" value="CA">Canada</option>
<option value="US">USA</option>
</select>
<br /><button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Nota:
No se recomienda usar ViewBag
o ViewData
con el asistente de etiquetas Select. Un modelo de vista es más eficaz a la hora de proporcionar metadatos MVC y suele ser menos problemático.
El valor de atributo asp-for
es un caso especial y no necesita un prefijo Model
, mientras que los otros atributos del asistente de etiquetas sí (como asp-items
).
<select asp-for="Country" asp-items="Model.Countries"></select>
Enlace con enum
A menudo, conviene usar <select>
con una propiedad enum
y generar los elementos SelectListItem
a partir de valores enum
.
Sample:
public class CountryEnumViewModel
{
public CountryEnum EnumCountry { get; set; }
}
using System.ComponentModel.DataAnnotations;
namespace FormsTagHelper.ViewModels
{
public enum CountryEnum
{
[Display(Name = "United Mexican States")]
Mexico,
[Display(Name = "United States of America")]
USA,
Canada,
France,
Germany,
Spain
}
}
El método GetEnumSelectList
genera un objeto SelectList
para una enumeración.
@model CountryEnumViewModel
<form asp-controller="Home" asp-action="IndexEnum" method="post">
<select asp-for="EnumCountry"
asp-items="Html.GetEnumSelectList<CountryEnum>()">
</select>
<br /><button type="submit">Register</button>
</form>
Puede marcar la lista de enumeradores con el atributo Display
para obtener una interfaz de usuario más completa:
using System.ComponentModel.DataAnnotations;
namespace FormsTagHelper.ViewModels
{
public enum CountryEnum
{
[Display(Name = "United Mexican States")]
Mexico,
[Display(Name = "United States of America")]
USA,
Canada,
France,
Germany,
Spain
}
}
Se genera el siguiente código HTML:
<form method="post" action="/Home/IndexEnum">
<select data-val="true" data-val-required="The EnumCountry field is required."
id="EnumCountry" name="EnumCountry">
<option value="0">United Mexican States</option>
<option value="1">United States of America</option>
<option value="2">Canada</option>
<option value="3">France</option>
<option value="4">Germany</option>
<option selected="selected" value="5">Spain</option>
</select>
<br /><button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Agrupamiento de opciones
El elemento HTML <optgroup> se genera cuando el modelo de vista contiene uno o más objetos SelectListGroup
.
CountryViewModelGroup
agrupa los elementos SelectListItem
en los grupos "North America" y "Europe":
public class CountryViewModelGroup
{
public CountryViewModelGroup()
{
var NorthAmericaGroup = new SelectListGroup { Name = "North America" };
var EuropeGroup = new SelectListGroup { Name = "Europe" };
Countries = new List<SelectListItem>
{
new SelectListItem
{
Value = "MEX",
Text = "Mexico",
Group = NorthAmericaGroup
},
new SelectListItem
{
Value = "CAN",
Text = "Canada",
Group = NorthAmericaGroup
},
new SelectListItem
{
Value = "US",
Text = "USA",
Group = NorthAmericaGroup
},
new SelectListItem
{
Value = "FR",
Text = "France",
Group = EuropeGroup
},
new SelectListItem
{
Value = "ES",
Text = "Spain",
Group = EuropeGroup
},
new SelectListItem
{
Value = "DE",
Text = "Germany",
Group = EuropeGroup
}
};
}
public string Country { get; set; }
public List<SelectListItem> Countries { get; }
Aquí mostramos los dos grupos:
El código HTML generado:
<form method="post" action="/Home/IndexGroup">
<select id="Country" name="Country">
<optgroup label="North America">
<option value="MEX">Mexico</option>
<option value="CAN">Canada</option>
<option value="US">USA</option>
</optgroup>
<optgroup label="Europe">
<option value="FR">France</option>
<option value="ES">Spain</option>
<option value="DE">Germany</option>
</optgroup>
</select>
<br /><button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Selección múltiple
El asistente de etiquetas selectas generará automáticamente el atributo multiple = "multiple" si la propiedad especificada en el atributo asp-for
es un IEnumerable
. Por ejemplo, si tenemos el siguiente modelo:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace FormsTagHelper.ViewModels
{
public class CountryViewModelIEnumerable
{
public IEnumerable<string> CountryCodes { get; set; }
public List<SelectListItem> Countries { get; } = new List<SelectListItem>
{
new SelectListItem { Value = "MX", Text = "Mexico" },
new SelectListItem { Value = "CA", Text = "Canada" },
new SelectListItem { Value = "US", Text = "USA" },
new SelectListItem { Value = "FR", Text = "France" },
new SelectListItem { Value = "ES", Text = "Spain" },
new SelectListItem { Value = "DE", Text = "Germany"}
};
}
}
Con la siguiente vista:
@model CountryViewModelIEnumerable
<form asp-controller="Home" asp-action="IndexMultiSelect" method="post">
<select asp-for="CountryCodes" asp-items="Model.Countries"></select>
<br /><button type="submit">Register</button>
</form>
Se genera el siguiente código HTML:
<form method="post" action="/Home/IndexMultiSelect">
<select id="CountryCodes"
multiple="multiple"
name="CountryCodes"><option value="MX">Mexico</option>
<option value="CA">Canada</option>
<option value="US">USA</option>
<option value="FR">France</option>
<option value="ES">Spain</option>
<option value="DE">Germany</option>
</select>
<br /><button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Sin selección
Si ve que usa la opción "sin especificar" en varias páginas, puede crear una plantilla para no tener que repetir el código HTML:
@model CountryViewModel
<form asp-controller="Home" asp-action="IndexEmpty" method="post">
@Html.EditorForModel()
<br /><button type="submit">Register</button>
</form>
La plantilla Views/Shared/EditorTemplates/CountryViewModel.cshtml
:
@model CountryViewModel
<select asp-for="Country" asp-items="Model.Countries">
<option value="">--none--</option>
</select>
La adición de elementos HTML <option> no se limita al caso Sin selección. Por ejemplo, el método de acción y vista siguientes generarán un código HTML similar al código anterior:
public IActionResult IndexNone()
{
var model = new CountryViewModel();
model.Countries.Insert(0, new SelectListItem("<none>", ""));
return View(model);
}
@model CountryViewModel
<form asp-controller="Home" asp-action="IndexEmpty" method="post">
<select asp-for="Country">
<option value=""><none></option>
<option value="MX">Mexico</option>
<option value="CA">Canada</option>
<option value="US">USA</option>
</select>
<br /><button type="submit">Register</button>
</form>
Se seleccionará el elemento <option>
correcto (que contenga el atributo selected="selected"
) en función del valor real de Country
.
public IActionResult IndexOption(int id)
{
var model = new CountryViewModel();
model.Country = "CA";
return View(model);
}
<form method="post" action="/Home/IndexEmpty">
<select id="Country" name="Country">
<option value=""><none></option>
<option value="MX">Mexico</option>
<option value="CA" selected="selected">Canada</option>
<option value="US">USA</option>
</select>
<br /><button type="submit">Register</button>
<input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>">
</form>
Recursos adicionales
- Asistentes de etiquetas en ASP.NET Core
- HTML Form element (Elemento HTML Form)
- Request Verification Token (Token de comprobación de solicitudes)
- Enlace de modelos en ASP.NET Core
- Validación de modelos en ASP.NET Core MVC
- IAttributeAdapter Interface (Interfaz IAttributeAdapter)
- Fragmentos de código de este documento