Solución:
Uso de los ayudantes Seleccionar etiqueta para representar un elemento SELECT
En su acción GET, cree un objeto de su modelo de vista, cargue el EmployeeList
propiedad de colección y envíelo a la vista.
public IActionResult Create()
{
var vm = new MyViewModel();
vm.EmployeesList = new List<Employee>
{
new Employee { Id = 1, FullName = "Shyju" },
new Employee { Id = 2, FullName = "Bryan" }
};
return View(vm);
}
Y en su vista de creación, cree una nueva SelectList
objeto del EmployeeList
propiedad y pasar eso como valor para el asp-items
propiedad.
@model MyViewModel
<form asp-controller="Home" asp-action="Create">
<select asp-for="EmployeeId"
asp-items="@(new SelectList(Model.EmployeesList,"Id","FullName"))">
<option>Please select one</option>
</select>
<input type="submit"/>
</form>
Y su método de acción HttpPost para aceptar los datos del formulario enviado.
[HttpPost]
public IActionResult Create(MyViewModel model)
{
// check model.EmployeeId
// to do : Save and redirect
}
O
Si su modelo de vista tiene un List<SelectListItem>
como propiedad de los elementos desplegables.
public class MyViewModel
{
public int EmployeeId { get; set; }
public string Comments { get; set; }
public List<SelectListItem> Employees { set; get; }
}
Y en tu acción,
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "1"},
new SelectListItem {Text = "Sean", Value = "2"}
};
return View(vm);
}
Y en la vista, puede usar directamente el Employees
propiedad para el asp-items
.
@model MyViewModel
<form asp-controller="Home" asp-action="Create">
<label>Comments</label>
<input type="text" asp-for="Comments"/>
<label>Lucky Employee</label>
<select asp-for="EmployeeId" asp-items="@Model.Employees" >
<option>Please select one</option>
</select>
<input type="submit"/>
</form>
La clase SelectListItem
pertenece a Microsoft.AspNet.Mvc.Rendering
espacio de nombres.
Asegúrese de utilizar una etiqueta de cierre explícita para el elemento seleccionado. Si usa el enfoque de etiqueta de cierre automático, el asistente de etiqueta representará un elemento SELECT vacío.
El siguiente enfoque no trabajará
<select asp-for="EmployeeId" asp-items="@Model.Employees" />
Pero esto funcionará.
<select asp-for="EmployeeId" asp-items="@Model.Employees"></select>
Obtener datos de la tabla de su base de datos usando el marco de la entidad
Los ejemplos anteriores utilizan elementos codificados de forma rígida para las opciones. Así que pensé en agregar un código de muestra para obtener datos usando Entity framework, ya que mucha gente lo usa.
Supongamos que su objeto DbContext tiene una propiedad llamada Employees
, que es de tipo DbSet<Employee>
donde el Employee
la clase de entidad tiene un Id
y Name
propiedad como esta
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
}
Puede usar una consulta LINQ para obtener los empleados y usar el método Select en su expresión LINQ para crear una lista de SelectListItem
objetos para cada empleado.
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = context.Employees
.Select(a => new SelectListItem() {
Value = a.Id.ToString(),
Text = a.Name
})
.ToList();
return View(vm);
}
Asumiendo context
es su objeto de contexto db. El código de vista es el mismo que el anterior.
Usando SelectList
Algunas personas prefieren usar SelectList
class para contener los elementos necesarios para representar las opciones.
public class MyViewModel
{
public int EmployeeId { get; set; }
public SelectList Employees { set; get; }
}
Ahora, en su acción GET, puede usar el SelectList
constructor para poblar el Employees
propiedad del modelo de vista. Asegúrese de especificar el dataValueField
y dataTextField
parámetros.
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new SelectList(GetEmployees(),"Id","FirstName");
return View(vm);
}
public IEnumerable<Employee> GetEmployees()
{
// hard coded list for demo.
// You may replace with real data from database to create Employee objects
return new List<Employee>
{
new Employee { Id = 1, FirstName = "Shyju" },
new Employee { Id = 2, FirstName = "Bryan" }
};
}
Aquí estoy llamando al GetEmployees
método para obtener una lista de objetos Empleado, cada uno con un Id
y FirstName
propiedad y uso esas propiedades como DataValueField
y DataTextField
de El SelectList
objeto que creamos. Puede cambiar la lista codificada por un código que lee datos de una tabla de base de datos.
El código de vista será el mismo.
<select asp-for="EmployeeId" asp-items="@Model.Employees" >
<option>Please select one</option>
</select>
Renderice un elemento SELECT de una lista de cadenas.
A veces, es posible que desee representar un elemento seleccionado de una lista de cadenas. En ese caso, puede utilizar el SelectList
constructor que solo toma IEnumerable<T>
var vm = new MyViewModel();
var items = new List<string> {"Monday", "Tuesday", "Wednesday"};
vm.Employees = new SelectList(items);
return View(vm);
El código de vista será el mismo.
Configurar las opciones seleccionadas
Algunas veces, es posible que desee establecer una opción como la opción predeterminada en el elemento SELECT (por ejemplo, en una pantalla de edición, desea cargar el valor de la opción guardada previamente). Para hacer eso, simplemente puede configurar el EmployeeId
valor de la propiedad al valor de la opción que desea seleccionar.
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "11"},
new SelectListItem {Text = "Tom", Value = "12"},
new SelectListItem {Text = "Jerry", Value = "13"}
};
vm.EmployeeId = 12; // Here you set the value
return View(vm);
}
Esto seleccionará la opción Tom en el elemento de selección cuando se renderice la página.
Menú desplegable de selección múltiple
Si desea renderizar un menú desplegable de selección múltiple, simplemente puede cambiar la propiedad del modelo de vista que usa para asp-for
atributo en su vista a un tipo de matriz.
public class MyViewModel
{
public int[] EmployeeIds { get; set; }
public List<SelectListItem> Employees { set; get; }
}
Esto representará el marcado HTML para el elemento seleccionado con el multiple
atributo que permitirá al usuario seleccionar múltiples opciones.
@model MyViewModel
<select id="EmployeeIds" multiple="multiple" name="EmployeeIds">
<option>Please select one</option>
<option value="1">Shyju</option>
<option value="2">Sean</option>
</select>
Configuración de las opciones seleccionadas en selección múltiple
Similar a la selección única, establezca el EmployeeIds
valor de la propiedad a la matriz de valores que desee.
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "11"},
new SelectListItem {Text = "Tom", Value = "12"},
new SelectListItem {Text = "Jerry", Value = "13"}
};
vm.EmployeeIds= new int[] { 12,13} ;
return View(vm);
}
Esto seleccionará la opción Tom y Jerry en el elemento de selección múltiple cuando se renderice la página.
Usar ViewBag para transferir la lista de elementos
Si no prefiere mantener una propiedad de tipo de colección para pasar la lista de opciones a la vista, puede usar el ViewBag dinámico para hacerlo. (Este no es mi enfoque recomendado personalmente, ya que viewbag es dinámico y su código es propenso a errores tipográficos no detectados.)
public IActionResult Create()
{
ViewBag.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "1"},
new SelectListItem {Text = "Sean", Value = "2"}
};
return View(new MyViewModel());
}
y en la vista
<select asp-for="EmployeeId" asp-items="@ViewBag.Employees">
<option>Please select one</option>
</select>
Usar ViewBag para transferir la lista de elementos y configurar la opción seleccionada
Es igual que arriba. Todo lo que tiene que hacer es establecer el valor de la propiedad (para la que está vinculando el menú desplegable) al valor de la opción que desea seleccionar.
public IActionResult Create()
{
ViewBag.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "1"},
new SelectListItem {Text = "Bryan", Value = "2"},
new SelectListItem {Text = "Sean", Value = "3"}
};
vm.EmployeeId = 2; // This will set Bryan as selected
return View(new MyViewModel());
}
y en la vista
<select asp-for="EmployeeId" asp-items="@ViewBag.Employees">
<option>Please select one</option>
</select>
Agrupar elementos
El método auxiliar de selección de etiquetas admite opciones de agrupación en un menú desplegable. Todo lo que tiene que hacer es especificar el Group
valor de propiedad de cada uno SelectListItem
en su método de acción.
public IActionResult Create()
{
var vm = new MyViewModel();
var group1 = new SelectListGroup { Name = "Dev Team" };
var group2 = new SelectListGroup { Name = "QA Team" };
var employeeList = new List<SelectListItem>()
{
new SelectListItem() { Value = "1", Text = "Shyju", Group = group1 },
new SelectListItem() { Value = "2", Text = "Bryan", Group = group1 },
new SelectListItem() { Value = "3", Text = "Kevin", Group = group2 },
new SelectListItem() { Value = "4", Text = "Alex", Group = group2 }
};
vm.Employees = employeeList;
return View(vm);
}
No hay cambios en el código de vista. el asistente de etiqueta de selección ahora mostrará las opciones dentro de 2 elementos de optgroup.
Creé una interfaz y un <options>
ayudante de etiquetas para esto. Entonces no tuve que convertir el IEnumerable<T>
elementos en IEnumerable<SelectListItem>
cada vez que tengo que poblar el <select>
control.
Y creo que funciona de maravilla …
El uso es algo como:
<select asp-for="EmployeeId">
<option value="">Please select...</option>
<options asp-items="@Model.EmployeesList" />
</select>
Y para que funcione con el asistente de etiquetas, debe implementar esa interfaz en su clase:
public class Employee : IIntegerListItem
{
public int Id { get; set; }
public string FullName { get; set; }
public int Value { return Id; }
public string Text{ return FullName ; }
}
Estos son los códigos necesarios:
La interfaz:
public interface IIntegerListItem
{
int Value { get; }
string Text { get; }
}
los <options>
ayudante de etiquetas:
[HtmlTargetElement("options", Attributes = "asp-items")]
public class OptionsTagHelper : TagHelper
{
public OptionsTagHelper(IHtmlGenerator generator)
{
Generator = generator;
}
[HtmlAttributeNotBound]
public IHtmlGenerator Generator { get; set; }
[HtmlAttributeName("asp-items")]
public object Items { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.SuppressOutput();
// Is this <options /> element a child of a <select/> element the SelectTagHelper targeted?
object formDataEntry;
context.Items.TryGetValue(typeof(SelectTagHelper), out formDataEntry);
var selectedValues = formDataEntry as ICollection<string>;
var encodedValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (selectedValues != null && selectedValues.Count != 0)
{
foreach (var selectedValue in selectedValues)
{
encodedValues.Add(Generator.Encode(selectedValue));
}
}
IEnumerable<SelectListItem> items = null;
if (Items != null)
{
if (Items is IEnumerable)
{
var enumerable = Items as IEnumerable;
if (Items is IEnumerable<SelectListItem>)
items = Items as IEnumerable<SelectListItem>;
else if (Items is IEnumerable<IIntegerListItem>)
items = ((IEnumerable<IIntegerListItem>)Items).Select(x => new SelectListItem() { Selected = false, Value = ((IIntegerListItem)x).Value.ToString(), Text = ((IIntegerListItem)x).Text });
else
throw new InvalidOperationException(string.Format("The {2} was unable to provide metadata about '{1}' expression value '{3}' for <options>.",
"<options>",
"ForAttributeName",
nameof(IModelMetadataProvider),
"For.Name"));
}
else
{
throw new InvalidOperationException("Invalid items for <options>");
}
foreach (var item in items)
{
bool selected = (selectedValues != null && selectedValues.Contains(item.Value)) || encodedValues.Contains(item.Value);
var selectedAttr = selected ? "selected='selected'" : "";
if (item.Value != null)
output.Content.AppendHtml($"<option value="{item.Value}" {selectedAttr}>{item.Text}</option>");
else
output.Content.AppendHtml($"<option>{item.Text}</option>");
}
}
}
}
Puede que haya algún error tipográfico, pero creo que el objetivo es claro. Tuve que editar un poco.
También puedes usar IHtmlHelper.GetEnumSelectList.
// Summary:
// Returns a select list for the given TEnum.
//
// Type parameters:
// TEnum:
// Type to generate a select list for.
//
// Returns:
// An System.Collections.Generic.IEnumerable`1 containing the select list for the
// given TEnum.
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if TEnum is not an System.Enum or if it has a System.FlagsAttribute.
IEnumerable<SelectListItem> GetEnumSelectList<TEnum>() where TEnum : struct;