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

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

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


person Community    schedule 20.10.2008    source источник
comment
Другие могут найти это решение полезным: stackoverflow.com/questions/3291501/   -  person Aaron    schedule 21.07.2010


Ответы (22)


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

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

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

person Dylan Beattie    schedule 20.10.2008
comment
Ага! Это то, что мне приходилось делать и для своих приложений! - person Adhip Gupta; 21.10.2008
comment
веселье скрытые поля ввода с таким же именем в качестве элемента управления. это ViewState 2.0! - person Simon_Weaver; 26.01.2009
comment
Это также присутствует в версии 1.0. Посмотрите на ответ @andrea-balducci, который дает вам разумный способ справиться с этим. Если флажок не установлен, полученный текст должен иметь значение «false false» - это хороший обходной путь для учета мертвых браузеров ... - person Bryan Rehbein; 27.03.2009
comment
Сюрприз? Wtf? Скрытый ввод имеет то же имя, что и флажок - если флажок с тем же именем не отмечен, его значение не публикуется, тогда как значение скрытого публикуется. Когда браузер впервые встречает именованный элемент, он будет использовать это значение и проигнорировать все другие элементы с таким же именем. Это гарантирует, что значение отправлено: true, если флажок установлен (при условии, что он находится над скрытым элементом), и false, если флажок не установлен (пустой флажок игнорируется, а скрытый становится откатом). Настоящая чушь - это то, почему никто не указал на это. - person nerraga; 18.08.2009
comment
@nerraga: Вы ошибаетесь: в html допустимо иметь несколько элементов формы с одним и тем же именем; и если это так, то размещаются все элементы, и я не уверен, что порядок действительно определен (хотя на практике, скорее всего, это просто порядок страниц). Использование слова false в качестве значения несколько вводит в заблуждение, так что да, это WTF - лучшим, менее вводящим в заблуждение выбором было бы что-то вроде exists или какой-то бессмысленный токен, например тире. - person Eamon Nerbonne; 08.12.2010
comment
@nerrega wtf! Я сделал! 26 января 2009 года! см. ниже - или выше - или здесь stackoverflow.com/a/479220/16940 - person Simon_Weaver; 21.09.2012

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

bool bChecked = form[key].Contains("true");
person Andrea Balducci    schedule 12.01.2009
comment
Это самый простой подход к этой проблеме, и я всегда им пользуюсь. Он позволяет использовать вспомогательные методы и учитывать поведение ASP.NET MVC. - person Nick Daniels; 19.11.2010
comment
.. или в случае отсутствия проверки: bool bChecked = form [key] .Equals (false); Выполнение .Contains (false) не выполняется, поскольку истинное значение равно true, false. - person Mark Robinson; 24.01.2011

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

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

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

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

person Simon_Weaver    schedule 26.01.2009
comment
Да, это удобно в сценариях, когда у вас есть страничные сетки и т. Д., И вы хотите отменить выбор элемента, который был ранее выбран в каком-то бизнес-объекте. - person RichardOD; 31.07.2009

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

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

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

person Simon_Weaver    schedule 26.01.2009

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

Посетите мою запись в блоге Больше подробностей.

person Shawn Mclean    schedule 16.10.2011
comment
Спасибо! Everboyd все еще использует старые формы. И когда вы отправляете, вы можете получить доступ к модели без всего этого мусора collection [] и request.form - это то, что я искал. +1 и + пиво - person Piotr Kula; 11.03.2013
comment
Это должен быть главный ответ на вопрос. Очень просто и легко реализовать. - person Johan Gunawan; 12.11.2014
comment
Некоторое время я пытался найти элегантное решение этой проблемы, прежде чем нашел этот ответ. Ему несколько лет, но он все еще актуален в 2016 году! При использовании в нескольких экземплярах используйте встроенный SelectListItem в качестве универсального типа, который идеально подходит для этого. - person Phil; 05.01.2016
comment
SampleObject - это список? Например: @ModelType List (Of Type) - person JoshYates1980; 10.06.2016

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

Вид:


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

Контроллер:


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

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

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

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

person mmacaulay    schedule 20.10.2008
comment
Я просто хочу добавить альтернативный пример: Object.Property =! String.IsNullOrEmpty (Request.Form [NAME]); - person Gup3rSuR4c; 05.05.2010
comment
если не отмечен, то он переходит в исключение - person Xulfee; 28.02.2011

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

model.Property = collection["ElementId"].ToLower().StartsWith("true");
person Fluffy    schedule 20.03.2010

@Dylan Beattie Отличная находка !!! Большое спасибо. Чтобы расширить еще больше, этот метод также отлично работает с подходом модели представления. 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" />
<%}%>                    

Controller:

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

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

person nautic20    schedule 04.06.2010
comment
Спасибо, ваш SampleViewModel устранил некоторую путаницу в исходном ответе. - person parliament; 22.12.2012

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

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

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

person Darcy    schedule 22.03.2010

<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";
         }
    }
person bluwater2001    schedule 21.06.2010

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

person Farhan Zia    schedule 18.01.2010

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

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

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

person BraveNewMath    schedule 22.05.2012

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

person Dan VanWinkle    schedule 14.06.2012
comment
есть ли причина, по которой вы используете Request.Params вместо добавления параметра FormCollection в метод? - person SwissCoder; 23.10.2012
comment
Нет причин, я действительно не вижу преимущества одного способа перед другим. - person Dan VanWinkle; 24.10.2012
comment
Извините, на самом деле причина есть. Просто взглянул на мой код, и я использую этот метод для 5 разных вызовов, и мне не хотелось передавать FormCollection из каждого метода. Это был самый простой способ получить ключи без необходимости что-либо передавать. - person Dan VanWinkle; 24.10.2012
comment
да, я новичок в MVC. И я где-то читал, что в целом лучше использовать FormCollection вместо Request.Params, так же, как использование типизированной модели вместо FormCollection (так что на самом деле было бы лучше использовать модель и избегать использования Request.Params в целом). Я заметил, что другие элементы кода не используются, например, переменная allPermissions и keyAsInt. Спасибо за ответы. - person SwissCoder; 24.10.2012

Проще всего сделать так ...

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

<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);
        }
person kk-dev11    schedule 05.01.2012

То же, что и ответ 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>
<% } %>
person ChinaHelloWorld    schedule 11.03.2014
comment
Спасибо за ответ, но этот вопрос juuuust немного устарел. Шесть лет, около. Возможно, вы захотите отредактировать и указать, какую версию MVC вы используете. Это поможет любому, кто использует более новую версию, найти этот ответ. - person ; 11.03.2014
comment
Я поддерживаю это. Удаление уникального идентификатора решило эту проблему после долгих головных болей и скрежета зубов. - person Ody; 22.04.2015
comment
Я использую версию MVC .net MVC 4.0 для решения этой проблемы. - person ChinaHelloWorld; 10.06.2015

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

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

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

person Jeroen    schedule 22.10.2010

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

bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
    ModelState.AddModelError(”chkHuman”, “Nice try.”);
person Skadoosh    schedule 11.11.2010

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

person eyesnz    schedule 20.04.2011

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

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

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

    }
});
person doronAv    schedule 10.08.2011
comment
К сожалению, вы можете получить странные результаты на стороне сервера для людей с отключенным JavaScript (плагин NoScript, старые мобильные телефоны, Lynx ...) - person ArIck; 16.09.2011

Мое решение:

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

person pawlom84    schedule 29.12.2010
comment
Для этого не нужно использовать какой-либо Javascript ... var isChecked = formData [key] .Contains (true); - person Jammer; 16.04.2013

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

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

Попробуйте ввести 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()" />
person treborian    schedule 17.04.2013

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

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

Если отмечено active = true

Если не отмечено, active = false

person Ravi Ram    schedule 25.02.2014