two - Como lidar com caixas de seleção em formulários ASP.NET MVC?




post form data asp net mvc (15)

@Dylan Beattie Grande Achado !!! Eu muito obrigado. Para expandir ainda mais, essa técnica também funciona perfeitamente com a abordagem do Modelo de Visualização. O MVC é tão legal, é inteligente o suficiente para ligar um array de Guids a uma propriedade pelo mesmo nome do objeto Model ligado à View. Exemplo:

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; }
    }
}

Visão:

<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();
    }

Qualquer pessoa familiarizada com a filosofia do Modelo View se regozija, isso funciona como um campeão!

Atenção: Esta questão tem mais de nove anos!

Sua melhor opção é pesquisar por perguntas mais recentes ou pesquisar as respostas abaixo procurando sua versão específica do MVC, já que muitas das respostas aqui estão obsoletas agora.

Se você encontrar uma resposta que funcione para a sua versão, certifique-se de que a resposta contenha a versão do MVC que você está usando.
(A pergunta original começa abaixo)

Isso parece um pouco bizarro para mim, mas tanto quanto eu posso dizer, é assim que você faz.

Eu tenho uma coleção de objetos e quero que os usuários selecionem um ou mais deles. Isso me diz "forma com caixas de seleção". Meus objetos não têm nenhum conceito de "selecionado" (eles são POCOs rudimentares formados pela desserialização de uma chamada wcf). Então, eu faço o seguinte:

public class SampleObject{
  public Guid Id {get;set;}
  public string Name {get;set;}
}

Na visão:

<%
    using (Html.BeginForm())
    {
%>
  <%foreach (var o in ViewData.Model) {%>
    <%=Html.CheckBox(o.Id)%>&nbsp;<%= o.Name %>
  <%}%>
  <input type="submit" value="Submit" />
<%}%>

E, no controlador, essa é a única maneira que vejo para descobrir quais objetos o usuário verificou:

public ActionResult ThisLooksWeird(FormCollection result)
{
  var winnars = from x in result.AllKeys
          where result[x] != "false"
          select x;
  // yadda
}

Seu freaky no primeiro lugar, e em segundo lugar, para os itens que o usuário verificou, o FormCollection lista seu valor como "verdadeiro falso" ao invés de apenas verdadeiro.

Obviamente, estou perdendo alguma coisa. Eu acho que isso é construído com a idéia em mente que os objetos na coleção que são acionados dentro do formulário html são atualizados usando UpdateModel() ou através de um ModelBinder.

Mas meus objetos não estão preparados para isso; Isso significa que esse é o único caminho? tem outro jeito de fazer isto?


A maneira mais fácil de fazer é tão ...

Você define o nome e o valor.

<input type="checkbox" name="selectedProducts" value="@item.ProductId" />@item.Name

Em seguida, ao enviar, pegue os valores das caixas de seleção e salve em uma matriz int. então a função LinQ apropriada. É isso aí..

[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);
        }

Apenas faça isso em $(document).ready :

$('input:hidden').each(function(el) {
    var that = $(this)[0];
    if(that.id.length < 1 ) {

        console.log(that.id);
        that.parentElement.removeChild(that);

    }
});

Aqui está o que eu tenho feito.

Visão:


<input type="checkbox" name="applyChanges" />

Controlador:


var checkBox = Request.Form["applyChanges"];

if (checkBox == "on")
{
...
}

Eu encontrei os métodos de ajuda Html. * Não tão úteis em alguns casos, e que eu era melhor fazê-lo em HTML simples. Sendo este um deles, o outro que vem à mente são botões de rádio.

Edit: isso é na pré-visualização 5, obviamente, YMMV entre as versões.


Eles parecem estar optando por ler apenas o primeiro valor, portanto, isso é "verdadeiro" quando a caixa de seleção está marcada e "false" quando apenas o valor oculto é incluído. Isso é facilmente obtido com código como este:

model.Property = collection["ElementId"].ToLower().StartsWith("true");

Esse problema está acontecendo na versão 1.0 também. Html.Checkbox () faz com que outro campo oculto seja adicionado com o mesmo nome / id da sua caixa de seleção original. E como eu estava tentando carregar uma matriz de caixa de seleção usando document.GetElemtentsByName (), você pode adivinhar como as coisas estavam ficando confusas. É um bizarro.


Eu sei que esta questão foi escrita quando MVC3 não estava fora, mas para quem vem a esta pergunta e está usando o MVC3, você pode querer a maneira "correta" de fazer isso.

Enquanto eu penso que fazer o todo

Contains("true");

A coisa é ótima e limpa, e funciona em todas as versões do MVC, o problema é que ela não leva em conta a cultura (como se isso realmente importasse no caso de um bool).

A maneira "correta" de descobrir o valor de um bool, pelo menos em MVC3, é usar o ValueProvider.

var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));

Eu faço isso em um dos sites do meu cliente quando edito permissões:

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));
}

Agora, a beleza disso é que você pode usar isso com praticamente qualquer tipo simples, e será até mesmo correto com base na Cultura (pense em dinheiro, decimais, etc).

O ValueProvider é o que é usado quando você forma suas ações assim:

public ActionResult UpdatePermissions(bool permission_1, bool permission_2)

mas quando você está tentando construir dinamicamente essas listas e verificar os valores, você nunca saberá o ID em tempo de compilação, então você precisa processá-los rapidamente.


Eu também gostaria de salientar que você pode nomear cada caixa de seleção com um nome diferente e ter esse nome como parte dos parâmetros actionresults.

Exemplo,

Visão:

 <%= 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) {
    ...
}

Os valores da exibição são passados ​​para a ação, pois os nomes são os mesmos.

Eu sei que esta solução não é ideal para o seu projeto, mas eu pensei em lançar a idéia lá fora.


Html.CheckBox está fazendo algo estranho - se você visualizar a fonte na página resultante, verá que há um <input type="hidden" /> sendo gerado ao lado de cada caixa de seleção, o que explica os valores "true false" que você está vendo para cada elemento de formulário.

Tente isso, o que definitivamente funciona no ASP.NET MVC Beta porque eu apenas tentei.

Coloque isso na visão em vez de usar o 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" />
<%}%>

Suas caixas de seleção são todas chamadas de selectedObjects , e o value de cada caixa de seleção é o GUID do objeto correspondente.

Em seguida, poste na seguinte ação do controlador (ou algo semelhante que faça algo útil em vez de Response.Write ())

public ActionResult ShowData(Guid[] selectedObjects) {
    foreach (Guid guid in selectedObjects) {
        Response.Write(guid.ToString());
    }
    Response.End();
    return (new EmptyResult());
}

Este exemplo irá apenas escrever os GUIDs das caixas que você verificou; A ASP.NET MVC mapeia os valores GUID das caixas de seleção selecionadas para o parâmetro Guid[] selectedObjects para você e ainda analisa as seqüências da coleção Request.Form em objetos GUID instanciados, o que eu acho bastante agradável.


HtmlHelper adiciona uma entrada oculta para notificar o controlador sobre o status Unchecked. Então, para ter o status verificado correto:

bool bChecked = form[key].Contains("true");

Minha solução é:

<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>  

Mais você pode encontrar aqui: http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a-valid-boolean/


Pelo que eu posso reunir, o modelo não quer adivinhar se checked = true ou false, eu contornei isso definindo um atributo de valor no elemento checkbox com jQuery antes de enviar o formulário da seguinte forma:

 $('input[type="checkbox"]').each(function () {
       $(this).attr('value', $(this).is(':checked'));
 }); 

Dessa forma, você não precisa de um elemento oculto apenas para armazenar o valor da caixa de seleção.


Usando @mmacaulay, eu inventei isso para bool:

// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");

Se marcado como ativo = verdadeiro

Se desmarcado, ativo = falso


Você também deve usar <label for="checkbox1">Checkbox 1</label> porque as pessoas podem clicar no texto da etiqueta e na própria caixa de seleção. Também é mais fácil de estilizar e, pelo menos no IE, ele será destacado quando você percorrer os controles da página.

<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>

Isto não é apenas uma coisa 'oh, eu poderia fazer isso'. É um aprimoramento significativo da experiência do usuário. Mesmo que nem todos os usuários saibam que podem clicar no rótulo, muitos o farão.


<input type = "checkbox" name = "checkbox1" /> <label> Check to say hi.</label>

Do Controlador:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Index(FormCollection fc)
    {

         var s = fc["checkbox1"];

         if (s == "on")
         {
             string x = "Hi";
         }
    }




checkbox