Подтвердить что ты не робот

Группа 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, но это работает.

4b9b3361

Ответ 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)/>
            &nbsp;<span>Supervisor</span><br />

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Auditor" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Auditor") ? "checked=true" : string.Empty)/>
            &nbsp;<span>Auditor</span><br />

            <input id="EmployeeRoles" name="EmployeeRoles" type="checkbox" value="Administrator" 
            @(Model.EmployeeRoles != null && Model.EmployeeRoles.Contains("Administrator") ? "checked=true" : string.Empty) />
            &nbsp;<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}&nbsp;<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))

Я использую перечисление, но вы можете использовать любую коллекцию