reusable checkbox partial view

99封情书 提交于 2019-12-02 01:53:59

问题


I have a partial view that uses a list (CheckBoxListModel) of classes (CheckBoxModel) with a string and bool to create a list of checkboxes. The code works to create the checkboxes and sends the selected ones back to the controller when the page posts. I am trying to find a way to make my partial reusable. As you can see in the code I send the partial the full Model and this works to get the updated checkboxes when the page posts. I tried to send my Model's CheckBoxListModel, but it does not work because when it creates the checkboxes the name is incorrect. I would like to reuse the partial by sending it a CheckBoxListModel so I do not have to create a separate partial every time I need a set of checkboxes.

I tried to change_CheckBoxListPartial.cshtml to

    @model MySite.Models.ViewModels.CheckBoxListModel
    ...
    @Html.EditorFor(x => x.CheckBoxes)
    ...

but without the clmReturnOptions the checkbox names end up as name="CheckBoxes[0].isChecked" instead of name="clmReturnOptions.CheckBoxes[0].isChecked" so they are not updated in the Model when the page posts and gets back to the controller.

I have been looking at: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ but still can't seem to get the checkboxes to work without sending the entire model to my partial.

CheckBoxListModel.cs

        public class CheckBoxListModel: ICheckBoxList
        {
            public IList<CheckBoxModel> CheckBoxes { get; set; }
            public string CheckBoxListTitle { get; set; }

            public CheckBoxListModel()
            {
            }
        }

        public class CheckBoxModel
        {
            public string CheckBoxName { get; set; }
            public string DisplayName { get; set; }
            public bool isChecked { get; set; }

            public CheckBoxModel()
            { }

            public CheckBoxModel(string checkboxname, string displayname, bool ischecked)
            {
                CheckBoxName = checkboxname;
                DisplayName = displayname;
                isChecked = ischecked;
            }
        }

        public interface ICheckBoxList
        {
            IList<CheckBoxModel> CheckBoxes { get; set; }
            string CheckBoxListTitle { get; set; }
        }

ReportFilterViewModel.cs

        public class ReportFilterViewModel
        {
            public ReportFilterViewModel()
            {
                clmReturnOptions = new CheckBoxListModel();
            }

            public CheckBoxListModel clmReturnOptions { get; set; }
        }

filters.cshtml <-- this is where the partial is called

    @model MySite.Areas.Reports.Models.ViewModels.ReportFilterViewModel
    ...
        @if (Model.Filters.IsReturnsOptionsAvailable)
        {
            Html.RenderPartial("_CheckBoxFilterPartial", Model.clmReturnOptions);
        }
    ...

_CheckBoxFilterPartial.cshtml

    @model MySite.Areas.Reports.Models.ViewModels.ICheckBoxList

    @{
        Layout = null;
    }

    <!DOCTYPE html>
    <html>
    <head>
        <title>Returns Options</title>
    </head>
    <body>
        <div class="col-md-4">
            <div class="plm prm ptm pbm configureCellSplitBG configureCellSplitBG-outline mtm">
                <div class="row mlm mrm">
                    <h6>@Model.CheckBoxListTitle</h6>
                </div>
                @Html.EditorFor(x => x.CheckBoxes)
            </div>
        </div>
    </body>
    </html>

CheckBoxModel.cshtml

    @model MySite.Areas.Reports.Models.ViewModels.CheckBoxModel
    <div class="row mlm mrm">
        <div class="form-group">
            <label class="checkbox">
                @Html.CheckBoxFor(x => x.isChecked, new { @data_toggle = "checkbox" })
                @Html.LabelFor(x => x.CheckBoxName, Model.DisplayName)
                @Html.HiddenFor(x => x.CheckBoxName)
            </label>
        </div>
    </div>

UPDATE When I view source I can see that the CheckBox names are still: name="CheckBoxes[0].isChecked" So when the model gets back to the controller the list is null

1 other change I made was moving the CheckBoxListModel.cs from MySite.Models.ViewModels to MySite.Areas.Reports.Models, since everything else is under the reports.models.

The problem seems to be the partial view. If I put @Html.EditorFor(x => x.clmReturnOptions.CheckBoxes) in my main page the checkboxes are created with the full name and are updated correctly. As soon as i tried to use the EditorFor in the partial view the checkbox name changes and the link to them back to the Model breaks. I would like to have this in a partial view so I do not have to add all the ui formating everywhere i want a checkbox list.

I have updated the above code


回答1:


You need to pass the prefix to the partial view so the elements are correctly named

@if (Model.Filters.IsReturnsOptionsAvailable)
{
  Html.RenderPartial("_CheckBoxFilterPartial", Model.clmReturnOptions, new ViewDataDictionary
  {
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "clmReturnOptions" }
  })
}

You can also write a custom html helper to make this a little easier

public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
  string name = ExpressionHelper.GetExpressionText(expression);
  object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
  var viewData = new ViewDataDictionary(helper.ViewData)
  {
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = name }
  };
  return helper.Partial(partialViewName, model, viewData);
}

and use as

@Html.PartialFor(m => m.clmReturnOptions, "_CheckBoxFilterPartial")



回答2:


Create an interface that provides access to the IList<CheckBoxModel>

public interface ICheckBoxList
{
    IList<CheckBoxModel> CheckBoxes { get; set; }
}

Have CheckBoxListModel implement that interface

public class CheckBoxListModel:ICheckBoxList
{...

Your _CheckBoxListPartial.cshtml partial view will use the new interface as its model

@model MySite.Areas.Reports.Models.ViewModels.ICheckBoxList

and change your EditorFor to

@Html.EditorFor(x => x.CheckBoxes)

I couldn't find the code in your question that showed how you are including the _CheckBoxListPartial partial view, but you would simply pass the clmReturnOptions property of the ViewModel (ReportFilterViewModel or otherwise) instead of the entire model.

And you should be good to go.



来源:https://stackoverflow.com/questions/27967080/reusable-checkbox-partial-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!