Как обрабатывать флажки в формах ASP.NET MVC?

Внимание: этот вопрос старше пяти лет!

Ваш лучший вариант - поиск новых вопросов или поиск ответов ниже в поисках вашей конкретной версии MVC, так как многие ответы здесь устарели.

Если вы нашли ответ, который работает для вашей версии, убедитесь, что ответ содержит версию MVC, которую вы используете.
(исходный вопрос начинается ниже)


Это кажется мне немного странным, но насколько я могу судить, так оно и есть.

У меня есть набор объектов, и я хочу, чтобы пользователи выбирали один или несколько из них. Это говорит мне "форму с флажками". У моих объектов нет понятия "выбранный" (они являются рудиментарным POCO, образованным десериализацией вызова wcf). Итак, я делаю следующее:

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

В представлении:

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

И, в контроллере, это единственный способ увидеть, какие объекты пользователь проверил:

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

В первую очередь это причудливо, а во-вторых, для тех элементов, которые пользователь проверил, FormCollection перечисляет его значение как "true false", а не просто true.

Очевидно, что я что-то упускаю. Я думаю, что это построено с учетом идеи, что объекты в коллекции, которые действуют в форме html, обновляются с помощью UpdateModel() или через ModelBinder.

Но мои объекты не настроены для этого; означает ли это, что это единственный способ? Есть ли другой способ сделать это?

Ответ 1

Html.CheckBox делает что-то странное - если вы просматриваете исходный код на результирующей странице, вы увидите, что рядом с каждым флажком создается <input type="hidden" />, в котором объясняются значения "истинные ложные", которые вы видите для каждой формы элемент.

Попробуйте это, что определенно работает на ASP.NET MVC Beta, потому что я только что попробовал.

Поместите это в представление вместо использования 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" />
<%}%>

Все ваши флажки называются selectedObjects, а value каждого флажка - это GUID соответствующего объекта.

Затем перейдите к следующему действию контроллера (или что-то подобное, что делает что-то полезное вместо Response.Write())

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

В этом примере будут записываться только GUID из отмеченных вами полей; ASP.NET MVC сопоставляет значения GUID выбранных флажков в параметре Guid[] selectedObjects для вас и даже анализирует строки из коллекции Request.Form в объекты с включенным GUID, что, по моему мнению, довольно приятное.

Ответ 2

HtmlHelper добавляет скрытый ввод, чтобы уведомить контроллер о статусе Unchecked. Итак, чтобы иметь правильный проверенный статус:

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

Ответ 3

Если вам интересно, ПОЧЕМУ они помещают скрытое поле с тем же именем, что и флажок, причина такова:

Комментарий от исходного кода MVCBetaSource\MVC\src\MvcFutures\Mvc\ ButtonsAndLinkExtensions.cs

Отметьте дополнительные флажки <input type="hidden".../> для флажков. Это касается сценариев, в которых снятые флажки не отправляются запрос. Отправка скрытого ввода дает возможность знать, что checkbox присутствует на странице, когда запрос был представлен.

Я думаю, что за кулисами им нужно знать это для привязки к параметрам в методах действий контроллера. Тогда вы могли бы иметь логическое состояние tri-state, предположительно (связанное с нулевым параметром bool). Я не пробовал, но я надеюсь, что это так.

Ответ 4

Вы также должны использовать <label for="checkbox1">Checkbox 1</label>, потому что тогда люди могут нажимать на текст ярлыка, а также на флажок. Его также легче стилизовать, и, по крайней мере, в IE он будет выделен при входе в элементы управления страницы.

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

Это не просто "о, я могу это сделать". Это значительно улучшает работу пользователя. Даже если не все пользователи знают, что они могут щелкнуть по ярлыку, многие будут.

Ответ 5

Я удивлен, что ни один из этих ответов не использовал встроенные функции MVC для этого.

Я написал сообщение в блоге об этом здесь, которое даже связывает метки с этим флажком. Я использовал папку EditorTemplate, чтобы сделать это чистым и модульным способом.

Вы просто получите новый файл в папке EditorTemplate, который выглядит следующим образом:

@model SampleObject

@Html.CheckBoxFor(m => m.IsChecked)
@Html.HiddenFor(m => m.Id)
@Html.LabelFor(m => m.IsChecked, Model.Id)

в вашем фактическом представлении, нет необходимости цитировать это, просто 1 строку кода:

@Html.EditorFor(x => ViewData.Model)

Посетите мой сообщение в блоге для более подробной информации.

Ответ 6

Вот что я делал.

Вид:


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

Контроллер:


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

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

Я обнаружил, что хелпер-методы Html. * не очень полезны в некоторых случаях и что мне было лучше делать это в обычном старом HTML. Это один из них, другой, который приходит на ум, - это радио кнопки.

Изменить: это предварительный просмотр 5, очевидно, YMMV между версиями.

Ответ 7

Кажется, что они предпочитают читать только первое значение, поэтому это "истинно", когда флажок установлен, и "false", когда включено только скрытое значение. Это легко получить с помощью кода, подобного этому:

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

Ответ 8

@Дилан Битти Отличная находка!!! Я благодарю вас. Для дальнейшего расширения этот метод также отлично работает с подходом View Model. MVC настолько классный, он достаточно умен, чтобы привязать массив Guids к свойству с тем же именем объекта Model, связанного с представлением. Пример:

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

Вид:

<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" />
<%}%>                    

Контроллер:

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

Любой, кто знаком с философией View Model, будет радоваться, это работает как Champ!

Ответ 9

Я также хотел бы указать, что вы можете назвать каждый флажок другим именем и иметь это имя в параметрах actionresults.

Пример

Вид:

 <%= Html.CheckBox("Rs232CheckBox", false, new { @id = "rs232" })%>RS-232

 <%= Html.CheckBox("Rs422CheckBox", false, new { @id = "rs422" })%>RS-422

Контроллер:

public ActionResults MyAction(bool Rs232CheckBox, bool Rs422CheckBox) {
    ...
}

Значения из представления передаются в действие, так как имена одинаковы.

Я знаю, что это решение не идеально подходит для вашего проекта, но я думал, что брошу эту идею там.

Ответ 10

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

Из контроллера:

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

         var s = fc["checkbox1"];

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

Ответ 11

Эта проблема также возникает в версии 1.0. Html.Checkbox() вызывает добавление другого скрытого поля с тем же именем/идентификатором, что и в вашем исходном флажке. И когда я пытался загружать блок checkbox с помощью document.GetElemtentsByName(), вы можете догадаться, как все обманывается. Это странно.

Ответ 12

Из того, что я могу собрать, модель не хочет угадывать, была ли check = true или false, я обошел это, установив атрибут value в элементе checkbox с jQuery перед отправкой формы следующим образом:

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

Таким образом, вам не нужен скрытый элемент, чтобы сохранить значение этого флажка.

Ответ 13

Я знаю, что этот вопрос был написан, когда MVC3 не вышел, но для тех, кто приходит к этому вопросу и использует MVC3, может потребоваться "правильный" способ сделать это.

Хотя я думаю, что выполнение всего

Contains("true");

вещь замечательная и чистая, и работает во всех версиях MVC, проблема в том, что она не учитывает культуру (как если бы это имело значение в случае bool).

"Правильный" способ определить значение bool, по крайней мере в MVC3, заключается в использовании ValueProvider.

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

Я делаю это на одном из моих клиентских сайтов, когда я редактирую разрешения:

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

Теперь, красота этого заключается в том, что вы можете использовать это практически с любым простым типом, и он будет даже правильным, основываясь на Культуре (думать деньги, десятичные знаки и т.д.).

ValueProvider - это то, что используется, когда вы формируете свои действия следующим образом:

public ActionResult UpdatePermissions(bool permission_1, bool permission_2)

но когда вы пытаетесь динамически создавать эти списки и проверять значения, вы никогда не узнаете Id во время компиляции, поэтому вам придется обрабатывать их на лету.

Ответ 14

То же, что и в ответе nautic20, просто используйте флажок привязки модели MVC по умолчанию с тем же именем, что и свойство коллекции string/int/enum в ViewModel. Вот и все.

Но одна проблема должна указывать. В каждом элементе флажка вы не должны помещать в него "Id", который повлияет на привязку модели MVC.

Следующий код будет работать для привязки к модели:

 <% foreach (var item in Model.SampleObjectList)
       { %>
        <tr>
            <td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
            <td><%= Html.Encode(item.Name)%></td>
        </tr>
 <% } %>

Следующие коды не будут привязываться к модели (разница здесь - это присвоенный идентификатор для каждого флажка)

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

Ответ 15

это то, что я сделал, чтобы потерять двойные значения при использовании Html.CheckBox(...

Replace("true,false","true").Split(',')

с четырьмя ящиками, отмеченными, непроверенными, непроверенными, проверенными правда, ложь, ложь, ложь, истина, ложь в правда, ложь, ложь, правда. просто то, что мне нужно

Ответ 16

Самый простой способ сделать это так...

Вы задаете имя и значение.

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

Затем при отправке возьмите значения флажков и сохраните их в массиве int. затем соответствующую функцию LinQ. Что это..

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

Ответ 17

Как насчет чего-то подобного?

bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues("chkHuman")[0], out isChecked) == false)
    ModelState.AddModelError("chkHuman", "Nice try.");

Ответ 18

Мое решение:

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

Подробнее вы можете найти здесь: http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a-valid-boolean/

Ответ 19

При использовании флажка HtmlHelper, я предпочитаю работать с опубликованными данными формы в виде массива. Я действительно не знаю, почему, я знаю, что другие методы работают, но я думаю, что я просто предпочитаю как можно больше обрабатывать разделенные запятыми строки как массивы.

Таким образом, выполнение "проверенного" или истинного теста будет следующим:

//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true"); 

Выполнение ложной проверки:

//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true"); 

Основное отличие состоит в том, чтобы использовать GetValues, поскольку он возвращается как массив.

Ответ 20

Просто сделайте это на $(document).ready:

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

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

    }
});

Ответ 21

У меня была почти такая же проблема, но возвращаемое значение моего контроллера было заблокировано другими значениями.

Нашел простое решение, но оно кажется немного грубым.

Попробуйте ввести Viewbag. в свой контроллер, и теперь вы дадите ему имя, например Viewbag.Checkbool

Теперь переключитесь на представление и попробуйте @Viewbag.Checkbool с этим вы получите значение из контроллера.

Параметры моего контроллера выглядят следующим образом:

public ActionResult Anzeigen(int productid = 90, bool islive = true)

и мой флажок будет обновляться следующим образом:

<input id="isLive" type="checkbox" checked="@ViewBag.Value" ONCLICK="window.location.href = '/MixCategory/Anzeigen?isLive=' + isLive.checked.toString()" />

Ответ 22

Используя @mmacaulay, я придумал это для bool:

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

Если флажок active = true

Если непроверено active = false