asp.net-mvc - example - checkbox mvc model
¿Cómo manejar las casillas de verificación en los formularios MVC de ASP.NET? (22)
¿Qué tal algo como esto?
bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
ModelState.AddModelError(”chkHuman”, “Nice try.”);
Precaución: ¡Esta pregunta tiene más de nueve años!
Su mejor opción es buscar nuevas preguntas o buscar las respuestas a continuación en busca de su versión específica de MVC, ya que muchas respuestas están obsoletas ahora.
Si encuentra una respuesta que funcione para su versión, asegúrese de que contenga la versión de MVC que está usando.
(La pregunta original comienza abajo)
Esto me parece un poco extraño, pero por lo que puedo decir, así es como lo haces.
Tengo una colección de objetos, y quiero que los usuarios seleccionen uno o más de ellos. Esto me dice "forma con casillas de verificación". Mis objetos no tienen ningún concepto de "seleccionado" (son POCO rudimentarios formados por la deserialización de una llamada wcf). Entonces, hago lo siguiente:
public class SampleObject{
public Guid Id {get;set;}
public string Name {get;set;}
}
En la vista:
<%
using (Html.BeginForm())
{
%>
<%foreach (var o in ViewData.Model) {%>
<%=Html.CheckBox(o.Id)%> <%= o.Name %>
<%}%>
<input type="submit" value="Submit" />
<%}%>
Y, en el controlador, esta es la única manera que puedo ver para averiguar qué objetos verificó el usuario:
public ActionResult ThisLooksWeird(FormCollection result)
{
var winnars = from x in result.AllKeys
where result[x] != "false"
select x;
// yadda
}
Es extraño en primer lugar, y en segundo lugar, para aquellos elementos que el usuario verificó, FormCollection muestra su valor como "verdadero falso" en lugar de solo verdadero.
Obviamente, me estoy perdiendo algo. Creo que esto se ha creado teniendo en cuenta la idea de que los objetos de la colección en los que se actúa en el formulario html se actualizan mediante UpdateModel()
o mediante un ModelBinder.
Pero mis objetos no están configurados para esto; ¿Eso significa que esta es la única manera? ¿Hay otra manera de hacerlo?
@Dylan Beattie Great Find !!! Muchas gracias. Para ampliar aún más, esta técnica también funciona a la perfección con el enfoque del modelo de vista. MVC es genial, es lo suficientemente inteligente como para unir una matriz de Guids a una propiedad con el mismo nombre del objeto Modelo vinculado a la Vista. Ejemplo:
ViewModel:
public class SampleViewModel
{
public IList<SampleObject> SampleObjectList { get; set; }
public Guid[] SelectedObjectIds { get; set; }
public class SampleObject
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}
Ver:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Sample View</h2>
<table>
<thead>
<tr>
<th>Checked</th>
<th>Object Name</th>
</tr>
</thead>
<% using (Html.BeginForm()) %>
<%{%>
<tbody>
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
</tbody>
</table>
<input type="submit" value="Submit" />
<%}%>
Controlador:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult SampleView(Guid id)
{
//Object to pass any input objects to the View Model Builder
BuilderIO viewModelBuilderInput = new BuilderIO();
//The View Model Builder is a conglomerate of repositories and methods used to Construct a View Model out of Business Objects
SampleViewModel viewModel = sampleViewModelBuilder.Build(viewModelBuilderInput);
return View("SampleView", viewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SampleView(SampleViewModel viewModel)
{
// The array of Guids successfully bound to the SelectedObjectIds property of the View Model!
return View();
}
Cualquiera que esté familiarizado con la filosofía Ver modelo se alegrará, ¡esto funciona como un campeón!
Cuando utilizo la casilla de verificación HtmlHelper, prefiero trabajar con los datos de formulario de casilla de verificación publicados como una matriz. Realmente no sé por qué, sé que los otros métodos funcionan, pero creo que prefiero tratar las cadenas separadas por comas como una matriz tanto como sea posible.
Así que hacer una prueba ''verificada'' o verdadera sería:
//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true");
Hacer una verificación falsa sería:
//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true");
La principal diferencia es usar GetValues
ya que esto se devuelve como una matriz.
De lo que puedo recopilar, el modelo no quiere adivinar si está marcado = verdadero o falso, resolví esto configurando un atributo de valor en el elemento de casilla de verificación con jQuery antes de enviar el formulario de esta manera:
$(''input[type="checkbox"]'').each(function () {
$(this).attr(''value'', $(this).is('':checked''));
});
De esta manera, no necesita un elemento oculto solo para almacenar el valor de la casilla de verificación.
En caso de que se pregunte POR QUÉ ponen un campo oculto con el mismo nombre que la casilla de verificación, el motivo es el siguiente:
Comentario del código fuente MVCBetaSource / MVC / src / MvcFutures / Mvc / ButtonsAndLinkExtensions.cs
Renderice un
<input type="hidden".../>
adicional para las casillas de verificación. Esto aborda los escenarios en los que las casillas de verificación no seleccionadas no se envían en la solicitud. El envío de una entrada oculta permite saber que la casilla de verificación estaba presente en la página cuando se envió la solicitud.
Supongo que entre bastidores necesitan saber esto para vincular los parámetros en los métodos de acción del controlador. Entonces podría tener un booleano tri-estatal, supongo (vinculado a un parámetro bool que admite nulos). No lo he intentado pero espero que eso sea lo que hicieron.
Este problema está ocurriendo en la versión 1.0 también. Html.Checkbox () hace que se agregue otro campo oculto con el mismo nombre / id que en su casilla de verificación original. Y mientras intentaba cargar una matriz de casillas de verificación utilizando document.GetElemtentsByName (), puedes adivinar cómo se complicaron las cosas. Es un bizarro.
Esto es lo que he estado haciendo.
Ver:
<input type="checkbox" name="applyChanges" />
Controlador:
var checkBox = Request.Form["applyChanges"];
if (checkBox == "on")
{
...
}
Encontré que los métodos de ayuda Html. * No eran tan útiles en algunos casos, y que era mejor hacerlo en HTML antiguo. Este es uno de ellos, el otro que viene a la mente son los botones de radio.
Edición: esto está en la Vista previa 5, obviamente YMMV entre versiones.
Html.CheckBox está haciendo algo extraño: si ve el código fuente en la página resultante, verá que se genera un <input type="hidden" />
junto a cada casilla de verificación, lo que explica los valores "verdaderos falsos" que está viendo. para cada elemento de la forma.
Prueba esto, que definitivamente funciona en ASP.NET MVC Beta porque lo acabo de probar.
Ponga esto en la vista en lugar de usar Html.CheckBox ():
<% using (Html.BeginForm("ShowData", "Home")) { %>
<% foreach (var o in ViewData.Model) { %>
<input type="checkbox" name="selectedObjects" value="<%=o.Id%>">
<%= o.Name %>
<%}%>
<input type="submit" value="Submit" />
<%}%>
Sus casillas de verificación se denominan selectedObjects
, y el value
de cada casilla de verificación es el GUID del objeto correspondiente.
Luego publique en la siguiente acción del controlador (o algo similar que haga algo útil en lugar de Response.Write ())
public ActionResult ShowData(Guid[] selectedObjects) {
foreach (Guid guid in selectedObjects) {
Response.Write(guid.ToString());
}
Response.End();
return (new EmptyResult());
}
Este ejemplo solo escribirá los GUID de las casillas que marcó; ASP.NET MVC asigna los valores GUID de las casillas de verificación seleccionadas en el parámetro Guid[] selectedObjects
para usted, e incluso analiza las cadenas de la colección Request.Form en objetos GUID instantáneos, lo que creo que es bastante bueno.
HtmlHelper agrega una entrada oculta para notificar al controlador sobre el estado Sin marcar. Entonces para tener el estado correcto verificado:
bool bChecked = form[key].Contains("true");
Igual que la respuesta de nautic20, simplemente use la lista de casilla de verificación de enlace del modelo por defecto de MVC con el mismo nombre que una propiedad de colección de string / int / enum en ViewModel. Eso es.
Pero hay que señalar una cuestión. En cada componente de la casilla de verificación, no debe poner "Id" en él, lo que afectará el enlace del modelo MVC.
El siguiente código funcionará para el enlace de modelos:
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
Los siguientes códigos no serán vinculantes al modelo (la diferencia aquí es su ID asignada para cada casilla de verificación)
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" id="[some unique key]" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
La forma más fácil de hacerlo es tan ...
Establece el nombre y el valor.
<input type="checkbox" name="selectedProducts" value="@item.ProductId" />@item.Name
Luego, al enviar, tome los valores de las casillas de verificación y guárdelos en una matriz int. entonces la función LinQ apropiada. Eso es..
[HttpPost]
public ActionResult Checkbox(int[] selectedObjects)
{
var selected = from x in selectedObjects
from y in db
where y.ObjectId == x
select y;
return View(selected);
}
Me sorprende que ninguna de estas respuestas haya utilizado las funciones MVC incorporadas para esto.
Escribí una publicación de blog sobre esto here , que incluso en realidad vincula las etiquetas a la casilla de verificación. Usé la carpeta EditorTemplate para lograr esto de una manera limpia y modular.
Simplemente terminarás con un nuevo archivo en la carpeta EditorTemplate que se verá así:
@model SampleObject
@Html.CheckBoxFor(m => m.IsChecked)
@Html.HiddenFor(m => m.Id)
@Html.LabelFor(m => m.IsChecked, Model.Id)
en su vista real, no habrá necesidad de hacer un bucle, simplemente 1 línea de código:
@Html.EditorFor(x => ViewData.Model)
Visita mi here para más detalles.
Mi solución es:
<input type="checkbox" id="IsNew-checkbox" checked="checked" />
<input type="hidden" id="IsNew" name="IsNew" value="true" />
<script language="javascript" type="text/javascript" >
$(''#IsNew-checkbox'').click(function () {
if ($(''#IsNew-checkbox'').is('':checked'')) {
$(''#IsNew'').val(''true'');
} else {
$(''#IsNew'').val(''false'');
}
});
</script>
Puede encontrar más información aquí: http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a-valid-boolean/
Parece que están optando por leer solo el primer valor, por lo que esto es "verdadero" cuando la casilla está marcada, y "falso" cuando solo se incluye el valor oculto. Esto es fácil de obtener con código como este:
model.Property = collection["ElementId"].ToLower().StartsWith("true");
Sé que esta pregunta se escribió cuando MVC3 no se publicó, pero para cualquier persona que llegue a esta pregunta y use MVC3, es posible que desee la forma "correcta" de hacerlo.
Si bien creo que haciendo el conjunto
Contains("true");
La cosa es genial y limpia, y funciona en todas las versiones de MVC, el problema es que no tiene en cuenta la cultura (como si realmente importara en el caso de un bool).
La forma "correcta" de averiguar el valor de un bool, al menos en MVC3, es usar el ValueProvider.
var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));
Hago esto en uno de los sitios de mi cliente cuando edito los permisos:
var allPermissionsBase = Request.Params.AllKeys.Where(x => x.Contains("permission_")).ToList();
var allPermissions = new List<KeyValuePair<int, bool>>();
foreach (var key in allPermissionsBase)
{
// Try to parse the key as int
int keyAsInt;
int.TryParse(key.Replace("permission_", ""), out keyAsInt);
// Try to get the value as bool
var value = (bool)ValueProvider.GetValue(key).ConvertTo(typeof(bool));
}
Ahora, la belleza de esto es que puede usar esto con casi cualquier tipo simple, e incluso será correcto en función de la Cultura (piense en dinero, decimales, etc.).
El ValueProvider es lo que se usa cuando usted forma sus Acciones de esta manera:
public ActionResult UpdatePermissions(bool permission_1, bool permission_2)
pero cuando intenta construir dinámicamente estas listas y verificar los valores, nunca sabrá el Id en el momento de la compilación, por lo que debe procesarlos sobre la marcha.
Solo haz esto en $(document).ready
:
$(''input:hidden'').each(function(el) {
var that = $(this)[0];
if(that.id.length < 1 ) {
console.log(that.id);
that.parentElement.removeChild(that);
}
});
También debe usar <label for="checkbox1">Checkbox 1</label>
porque las personas pueden hacer clic en el texto de la etiqueta así como en la propia casilla de verificación. También es más fácil de diseñar y, al menos en IE, se resaltará cuando pases por los controles de la página.
<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>
Esto no es solo una cosa de ''oh podría hacerlo''. Es una mejora significativa de la experiencia del usuario. Incluso si no todos los usuarios saben que pueden hacer clic en la etiqueta, muchos lo harán.
También me gustaría señalar que puede asignar un nombre diferente a cada casilla de verificación y que ese nombre forme parte de los parámetros de los resultados de la acción.
Ejemplo,
Ver:
<%= Html.CheckBox("Rs232CheckBox", false, new { @id = "rs232" })%>RS-232
<%= Html.CheckBox("Rs422CheckBox", false, new { @id = "rs422" })%>RS-422
Controlador:
public ActionResults MyAction(bool Rs232CheckBox, bool Rs422CheckBox) {
...
}
Los valores de la vista se pasan a la acción ya que los nombres son los mismos.
Sé que esta solución no es ideal para su proyecto, pero pensé que iba a lanzar la idea.
Tuve casi el mismo problema pero el valor de retorno de mi controlador fue bloqueado con otros valores.
Encontré una solución simple pero parece un poco rudo.
Intenta escribir Viewbag.
en su controlador y ahora le da un nombre como Viewbag.Checkbool
Ahora cambie a la Vista y pruebe este @Viewbag.Checkbool
con esto obtendrá el valor del Controlador.
Mis parámetros de controlador se ven así:
public ActionResult Anzeigen(int productid = 90, bool islive = true)
y mi casilla de verificación se actualizará así:
<input id="isLive" type="checkbox" checked="@ViewBag.Value" ONCLICK="window.location.href = ''/MixCategory/Anzeigen?isLive='' + isLive.checked.toString()" />
Usando @mmacaulay, se me ocurrió esto para bool:
// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");
Si está marcado activo = verdadero
Si no está activo activo = falso
esto es lo que hice para perder los valores dobles al usar el Html.CheckBox (...
Replace("true,false","true").Split('','')
con 4 casillas marcadas, sin marcar, sin marcar, marcadas, se convierte en verdadero, falso, falso, falso, verdadero, falso en verdadero, falso, falso, verdadero. justo lo que necesitaba
<input type = "checkbox" name = "checkbox1" /> <label> Check to say hi.</label>
Desde el controlador:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
var s = fc["checkbox1"];
if (s == "on")
{
string x = "Hi";
}
}