Группа Checkbox ASP.NET MVC
Я пытаюсь сформулировать обход для отсутствия "группы флажков" в ASP.NET MVC. Типичным способом реализации этого является наличие флажков с тем же именем, каждый со значением, которое он представляет.
<input type="checkbox" name="n" value=1 />
<input type="checkbox" name="n" value=2 />
<input type="checkbox" name="n" value=3 />
При отправке он будет разделять все значения на элемент запроса "n".. поэтому Request [ "n" ] == "1,2,3", если все три проверяются при отправке. В ASP.NET MVC вы можете иметь параметр n в качестве массива для принятия этого сообщения.
public ActionResult ActionName( int[] n ) { ... }
Все вышеописанное отлично работает. Проблема заключается в том, что когда проверка не выполняется, флажки не восстанавливаются в их проверенное состояние. Любые предложения.
Код проблемы: (я начал с проекта asp.net mvc по умолчанию)
контроллер
public class HomeController : Controller
{
public ActionResult Index()
{ var t = getTestModel("First");
return View(t);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestModelView t)
{ if(String.IsNullOrEmpty( t.TextBoxValue))
ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
var newView = getTestModel("Next");
return View(newView);
}
private TestModelView getTestModel(string prefix)
{ var t = new TestModelView();
t.Checkboxes = new List<CheckboxInfo>()
{ new CheckboxInfo(){Text = prefix + "1", Value="1", IsChecked=false},
new CheckboxInfo(){Text = prefix + "2", Value="2", IsChecked=false}
};
return t;
}
}
public class TestModelView
{ public string TextBoxValue { get; set; }
public List<CheckboxInfo> Checkboxes { get; set; }
}
public class CheckboxInfo
{ public string Text { get; set; }
public string Value { get; set; }
public bool IsChecked { get; set; }
}
}
ASPX
<%
using( Html.BeginForm() ){
%> <p><%= Html.ValidationSummary() %></p>
<p><%= Html.TextBox("TextBoxValue")%></p>
<p><%
int i = 0;
foreach (var cb in Model.Checkboxes)
{ %>
<input type="checkbox" name="Checkboxes[<%=i%>]"
value="<%= Html.Encode(cb.Value) %>" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %>
/><%= Html.Encode(cb.Text)%><br />
<% i++;
} %></p>
<p><input type="submit" value="submit" /></p>
<%
}
%>
Рабочий код
контроллер
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(TestModelView t)
{
if(String.IsNullOrEmpty( t.TextBoxValue))
{ ModelState.AddModelError("TextBoxValue", "TextBoxValue required.");
return View(t);
}
var newView = getTestModel("Next");
return View(newView);
}
ASPX
int i = 0;
foreach (var cb in Model.Checkboxes)
{ %>
<input type="checkbox" name="Checkboxes[<%=i%>].IsChecked" <%=cb.IsChecked ? "checked=\"checked\"" : String.Empty %> value="true" />
<input type="hidden" name="Checkboxes[<%=i%>].IsChecked" value="false" />
<input type="hidden" name="Checkboxes[<%=i%>].Value" value="<%= cb.Value %>" />
<input type="hidden" name="Checkboxes[<%=i%>].Text" value="<%= cb.Text %>" />
<%= Html.Encode(cb.Text)%><br />
<% i++;
} %></p>
<p><input type="submit" value="submit" /></p>
Конечно, что-то подобное можно было бы сделать с помощью Html Helpers, но это работает.
Ответы
Ответ 1
Я не знаю, как решить вашу проблему, но вы можете определить свои флажки с помощью этого кода:
<%= Html.CheckBox("n[0]") %><%= Html.Hidden("n[0]",false) %>
<%= Html.CheckBox("n[1]") %><%= Html.Hidden("n[1]",false) %>
<%= Html.CheckBox("n[2]") %><%= Html.Hidden("n[2]",false) %>
Скрытые поля нужны, потому что если флажок не установлен, форма не отправляет никакого значения. С скрытым полем он отправляет false.
Ваш метод отправки будет:
[HttpPost]
public ActionResult Test(bool[] n)
{
return View();
}
Это может быть не оптимальным, и я открыт для комментариев, но он работает:)
ИЗМЕНИТЬ
Расширенная версия:
<%= Html.CheckBox("n[0].Checked") %><%= Html.Hidden("n[0].Value",32) %><%= Html.Hidden("n[0].Checked",false) %>
<%= Html.CheckBox("n[1].Checked") %><%= Html.Hidden("n[1].Value",55) %><%= Html.Hidden("n[1].Checked",false) %>
<%= Html.CheckBox("n[2].Checked") %><%= Html.Hidden("n[2].Value",76) %><%= Html.Hidden("n[2].Checked",false) %>
Ваш метод отправки будет:
[HttpPost]
public ActionResult Test(CheckedValue[] n)
{
return View();
}
public class CheckedValue
{
public bool Checked { get; set; }
public bool Value { get; set; }
}
Я написал его без VS, поэтому может потребоваться небольшая коррекция.
Ответ 2
Вот окончательное решение:
public static class Helpers
{
public static string CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, int value) where TProperty: IEnumerable<int>
{
var groupName = GetPropertyName(propertySelector);
var modelValues = propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);
var svalue = value.ToString();
var builder = new TagBuilder("input");
builder.GenerateId(groupName);
builder.Attributes.Add("type", "checkbox");
builder.Attributes.Add("name", groupName);
builder.Attributes.Add("value", svalue);
var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.Contains(value)))
{
builder.Attributes.Add("checked", null);
}
return builder.ToString(TagRenderMode.Normal);
}
private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
{
var body = propertySelector.Body.ToString();
var firstIndex = body.IndexOf('.') + 1;
return body.Substring(firstIndex);
}
}
И на ваш взгляд:
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "1")%>(iv),<br />
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "2")%>(vi),<br />
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "3")%>(vii),<br />
<%= Html.CheckboxGroup(model => model.DocumentCoverCustom, "4")%>(ix)<br />
Ответ 3
Ну... флажки не узнают свое состояние сами по себе, особенно если вы не используете помощника Html.CheckBox(если да, см. ответ LuKLed). Вам нужно будет поместить проверенное состояние каждого окна в ViewData (или Model), а затем выполнить поиск в вашем представлении так или иначе.
Предупреждение: действительно уродливый код кода:
Контроллер:
//validation fails
ViewData["checkboxn"] = n;
return View();
Вид:
<% int[] n = (int[])ViewData["checkboxn"]; %>
<input type="checkbox" name="n" value=1 <%= n != null && n.Contains(1) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=2 <%= n != null && n.Contains(2) ? "checked=\"checked\"" : "" %> />
<input type="checkbox" name="n" value=3 <%= n != null && n.Contains(3) ? "checked=\"checked\"" : "" %> />
Все, что я делаю здесь, это передать массив n обратно в представление, и если он содержит значение для соответствующего флажка, добавив checked="checked"
к элементу.
Вы, вероятно, захотите реорганизовать это в свой собственный HtmlHelper или, конечно же, сделать это менее уродливым, конечно.
Ответ 4
Это решение может представлять интерес для тех, кто хочет использовать чистый/простой подход:
Поддерживать состояние динамического списка флажков в ASP.NET MVC
Я бы не рекомендовал использовать Html.CheckBox, если у вас нет супер простого одиночного флажка, привязанного к одному bool (или нескольким статическим не более). Когда вы начинаете иметь списки флажков в одном массиве или динамических флажках, с ними сложно работать, и вы в конечном итоге программируете весь мир на раздувании на стороне сервера только для того, чтобы справиться с недостатками и заставить все работать. Забудьте об этом и просто используйте чистое решение, ориентированное на HTML, и вы быстро и быстро работаете с меньшим количеством беспорядков, чтобы поддерживать его в будущем.
Ответ 5
Я знаю, что это должно быть безумно поздно, но просто заставляйте кого-то еще оказаться здесь.
MVC имеет способ обработать группы флажков.
в вашей модели просмотра:
[Показать (Name = "Какие кредитные карты принимаются:" )]
public string [] EmployeeRoles {get; задавать; }
На странице:
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Supervisor"
@(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Supervisor") ? "checked=true" : string.Empty)/>
<span>Supervisor</span><br />
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Auditor"
@(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Auditor") ? "checked=true" : string.Empty)/>
<span>Auditor</span><br />
<input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Administrator"
@(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Administrator") ? "checked=true" : string.Empty) />
<span>Administrator</span>
Я очень старался создавать эти элементы управления с помощью бритвы, но без кубиков. Он держит
создавая это скрытое поле, о котором вы все говорили. для вашей группы флажков
вам не нужно это скрытое поле, просто код, который я добавил выше. Вы можете создать html-помощник для создания этого кода для вас.
public static HtmlString CheckboxGroup<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> propertySelector, Type EnumType)
{
var groupName = GetPropertyName(propertySelector);
var modelValues = ModelMetadata.FromLambdaExpression(propertySelector, htmlHelper.ViewData).Model;//propertySelector.Compile().Invoke(htmlHelper.ViewData.Model);
StringBuilder literal = new StringBuilder();
foreach (var value in Enum.GetValues(EnumType))
{
var svalue = value.ToString();
var builder = new TagBuilder("input");
builder.GenerateId(groupName);
builder.Attributes.Add("type", "checkbox");
builder.Attributes.Add("name", groupName);
builder.Attributes.Add("value", svalue);
var contextValues = HttpContext.Current.Request.Form.GetValues(groupName);
if ((contextValues != null && contextValues.Contains(svalue)) || (modelValues != null && modelValues.ToString().Contains(svalue)))
{
builder.Attributes.Add("checked", null);
}
literal.Append(String.Format("</br>{1} <span>{0}</span>", svalue.Replace('_', ' '),builder.ToString(TagRenderMode.Normal)));
}
return (HtmlString)htmlHelper.Raw(literal.ToString());
}
private static string GetPropertyName<T, TProperty>(Expression<Func<T, TProperty>> propertySelector)
{
var body = propertySelector.Body.ToString();
var firstIndex = body.IndexOf('.') + 1;
return body.Substring(firstIndex);
}
на вашей странице используйте его так:
@Html.CheckboxGroup(m = > m.EmployeeRoles, typeof (Enums.EmployeeRoles))
Я использую перечисление, но вы можете использовать любую коллекцию