Как обрабатывать флажки в формах 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 отображает его значение как «истинное ложное», а не просто истинное.

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

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

20.10.2008 21:30:10
Другие могут найти это решение полезным: stackoverflow.com/questions/3291501/…
Aaron 21.07.2010 11:51:02
22 ОТВЕТА
РЕШЕНИЕ

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, что, на мой взгляд, довольно неплохо.

262
20.10.2008 21:49:11
Ага! Это то, что я должен был сделать для своих приложений!
Adhip Gupta 21.10.2008 00:14:44
WTF. скрытые поля ввода с тем же именем в качестве элемента управления. его ViewState 2.0!
Simon_Weaver 26.01.2009 09:20:31
Это также присутствует в версии 1.0. Посмотрите на ответ @ andrea-balducci, который дает вам разумный способ справиться с этим. Если этот флажок не установлен, получаемый текст должен быть «ложно ложным» - это хороший обходной путь для учета браузеров,
Bryan Rehbein 27.03.2009 20:03:54
Сюрприз? WTF? Скрытый ввод имеет то же имя, что и флажок - если флажок с тем же именем не отмечен, то его значение не публикуется, тогда как значение скрытого публикуется. Когда браузер в первый раз встречает именованный элемент, он использует это значение и игнорирует все остальные элементы с таким же именем. Это гарантирует отправку значения: true, если флажок установлен (при условии, что он находится над скрытым элементом), и false, если флажок не установлен (пустой флажок игнорируется, а скрытый становится отступом). Настоящий недоумение - вот почему никто не указал на это.
nerraga 17.08.2009 20:33:43
@nerraga: Вы не правы: допустимо использовать HTML с несколькими элементами формы с одинаковым именем; и если да, то все элементы размещены, и я не уверен, что порядок на самом деле определен (хотя, скорее всего, на практике он будет просто в порядке страниц). Использование слова «false» в качестве значения несколько вводит в заблуждение, так что да, это WTF - лучшим, менее вводящим в заблуждение выбором было бы что-то вроде «существует» или какой-то бессмысленный токен, такой как тире.
Eamon Nerbonne 8.12.2010 17:27:27

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

Посмотреть:


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

контроллер:


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

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

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

Изменить: это в Preview 5, очевидно, YMMV между версиями.

25
20.10.2008 21:59:51
Я просто хочу добавить альтернативный пример: Object.Property =! String.IsNullOrEmpty (Request.Form ["NAME"]);
Gup3rSuR4c 5.05.2010 00:26:16
если не
Xulfee 28.02.2011 10:17:59

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

bool bChecked = form[key].Contains("true");
95
12.01.2009 15:55:40
Это самый простой подход к этой проблеме, и это то, что я всегда использую. Это позволяет использовать вспомогательные методы и учетную запись поведения ASP.NET MVC.
Nick Daniels 19.11.2010 14:41:25
.. или в случае не проверено: bool bChecked = form [key] .Equals ("false"); Выполнение .Contains ("false") завершается ошибкой, поскольку истинное значение равно "true, false".
Mark Robinson 24.01.2011 11:25:57

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

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

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

49
27.03.2009 21:14:51

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

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

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

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

54
30.01.2009 00:05:49
Да, это удобно в сценариях, где у вас есть выгруженные сетки и т. Д., И вы хотите отменить выбор для элемента, который ранее был выбран в каком-либо бизнес-объекте.
RichardOD 31.07.2009 14:45:40

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

4
18.01.2010 11:23:28

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

model.Property = collection["ElementId"].ToLower().StartsWith("true");
10
20.03.2010 20:36:06

Я также хотел бы отметить, что вы можете присвоить каждому флажку свое имя и включить его в параметры 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) {
    ...
}

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

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

6
22.03.2010 14:48:25

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

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!

8
4.06.2010 15:24:48
Спасибо, ваш SampleViewModel прояснил некоторую путаницу в исходном ответе.
parliament 21.12.2012 22:04:36
<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";
         }
    }
5
21.06.2010 19:41:28

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

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

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

2
22.10.2010 16:07:08

Как насчет этого?

bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
    ModelState.AddModelError(”chkHuman”, Nice try.”);
0
11.11.2010 20:49:15

Мое решение:

<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- действительный-логический /

0
3.12.2012 15:15:48
Вам не нужно использовать какой-либо Javascript для этого ... var isChecked = formData [key] .Contains ("true");
Jammer 16.04.2013 08:36:35

При использовании флажка 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как это возвращает в виде массива.

0
20.04.2011 22:25:36

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

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

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

    }
});
0
10.08.2011 18:19:13
К сожалению, вы можете получить странные результаты на стороне сервера для людей с отключенным JavaScript (плагин NoScript, старые мобильные телефоны, Lynx ...)
ArIck 15.09.2011 21:55:26

Я удивлен, что ни один из этих ответов не использовал встроенные функции 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)

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

27
5.01.2016 20:42:47
Спасибо! Эвербойд все еще использует старые способы форм. И когда вы отправляете, вы можете получить доступ к Модели без всей этой коллекции [] и мусора request.form - это то, что я искал. +1и + пиво
Piotr Kula 11.03.2013 14:11:22
Это должно быть лучшим ответом на вопрос. Очень просто и легко реализовать.
Johan Gunawan 12.11.2014 18:20:55
Некоторое время пытался найти элегантное решение, прежде чем нашел ответ. Ему несколько лет, но он все еще в силе в 2016 году! При использовании в нескольких случаях используйте встроенный SelectListItem в качестве универсального типа, который идеально подходит для этого
Phil 5.01.2016 17:17:48
Является ли SampleObject списком? Например: @ModelType List (Of Type)
JoshYates1980 10.06.2016 20:52:58

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

Вы устанавливаете имя и значение.

<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);
        }
3
5.01.2012 16:10:31

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

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

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

4
22.05.2012 21:32:21

Я знаю, что этот вопрос был написан, когда 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 во время компиляции, поэтому вам придется обрабатывать их на лету.

4
24.10.2012 06:34:28
есть ли причина, по которой вы используете Request.Params вместо добавления параметра FormCollection в метод?
SwissCoder 23.10.2012 09:55:23
Нет причин, я не вижу никакой пользы от одного способа перед другим.
Dan VanWinkle 24.10.2012 06:52:52
Извините, на самом деле есть причина. Просто посмотрел на мой код, и я использую этот один метод для 5 различных вызовов, и я не чувствовал, что передавал FormCollection из каждого метода. Это был самый простой способ получить ключи без необходимости что-либо передавать.
Dan VanWinkle 24.10.2012 07:07:15
да, я новичок в MVC. И я где-то читал, что в общем случае лучше использовать FormCollection вместо Request.Params, так же, как использовать типизированную модель вместо FormCollection (так что на самом деле было бы лучше использовать модель и избегать использования Request.Params в целом). Я заметил, что другие части кода не используются, такие как переменная allPermissions и keyAsInt. Спасибо за ответы.
SwissCoder 24.10.2012 08:05:01

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

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

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

Теперь переключитесь на View и попробуйте это @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()" />
0
17.04.2013 08:15:22

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

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

Если отмечено активно = true

Если флажок не активен = false

0
25.02.2014 23:02: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>
<% } %>
3
11.03.2014 17:05:00
Спасибо за ответ, но этот вопрос немного устарел . Шесть лет, о. Вы можете отредактировать и указать, какую версию MVC вы используете. Это поможет любому, кто использует более новую версию, найти этот ответ.
user1228 11.03.2014 17:41:22
Я второй это. Удаление уникального удостоверения личности решило эту проблему после сильных головных болей и скрежета зубов
Ody 22.04.2015 09:22:42
Версия MVC, которую я использую, - .net MVC 4.0 для этой проблемы.
ChinaHelloWorld 10.06.2015 15:05:19