asp.net-mvc - 通过 AJAX 加载后,部分 View 的 View 模型未绑定(bind)到主视图模型的 View 模型

标签 asp.net-mvc asp.net-ajax

View 模型

//MainViewModel
    public class MainViewModel
    {
        public string UserID { get; set; }
        public string ServiceType { get; set; }
        public List<Service> Services {get; set;}
     }

     public class Service
     {
       public string ServiceID {get; set;}
       public string ServiceName {get; set;
     }

这是 View
//Index.cshtml
@model ParentViewModel
@{
  <div>
     @Html.DropDownListFor(model => model.UserID, new{onchange="ddSelectionChanged(this)"})
     <div id="services">
        //This is filled with the ajax
     </div>
 </div>
}

这是 AJAX 调用
<script> 
function ddSelectionChanged(element){
$('#services').load('@(Url.Action("GetServices"))?serviceType =' element.value);
};
</script>

这是 Controller
//Controller
public class UserServicesController : Controller
{
    public ActionResult Index()
    {
      return View();
    }

    public PartialViewResult GetServices(string serviceType)
    {
      //Service servicesViewModel = Fetch Services from DB
      return PartialView("PartialViews/Shared/_Services", servicesViewModel);
    }
}

这工作正常,部分 View 按预期呈现,但是当我发布索引时,MainViewModel 的属性“服务”返回“空”。问题是模型的“服务”属性没有重新绑定(bind)到 MainViewModel,因为它动态呈现为局部 View 。

如何在局部 View 渲染时或发布表单之前重新绑定(bind)模型?

最佳答案

当您发布到操作时,modelbinder 填充的唯一部分是发布的字段和数据。如果您失去了服务,那么您需要在表单中提供字段以在发布期间保留该数据。

例如,在您的 AJAX 返回的任何 HTML 中,您需要为 Service 上的每个属性包含隐藏输入之类的内容。 :

@Html.HiddenFor(m => m.ServiceID)
@Html.HiddenFor(m => m.ServiceName)

然后,当您的表单发布时,该数据将与其他所有内容一起发布,并且模型绑定(bind)器将能够填写您的 Services。适当列出。但是,您还需要注意生成的字段名称。特别是如果您的响应 AJAX 请求的操作返回的部分 View 使用像 List<Service> 这样的模型直接代替MainViewModel , 那么渲染的 HTML 将失去知道它应该绑定(bind)到一个名为 Services 的属性的上下文。 .换句话说,在您的 HTML 中,您的字段名称最终将类似于 [0].ServiceID而不是 Services[0].ServiceID .后者对于让模型绑定(bind)器正确处理发布的数据是必要的。

您可以通过传递自定义 ViewDataDictionary 来弥补这一点。给您的Html.PartialHtml.RenderPartial来电。通过定义一个新的 TemplateInfoHtmlFieldPrefix设置为所需的任何值,即:
@Html.Partial("_SomePartial", someModel, new ViewDataDictionary
{
    TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "SomePrefix" }
}

但是,返回 PartialView 时会比较棘手。直接,因为 PartialView不接受自定义参数 ViewDataDictionary .我自己没试过,但是可以设置HtmlFieldPrefix直接在您的操作中:
public PartialViewResult GetServices(string serviceType)
{
  ViewData.TemplateInfo.HtmlFieldPrefix = "Services";
  //Service servicesViewModel = Fetch Services from DB
  return PartialView("PartialViews/Shared/_Services", servicesViewModel);
}

另外值得一提的是,如果您以前没有使用过绑定(bind)集合,那么您需要使用 for循环而不是 foreach循环以便为字段名称提供适当的上下文。例如,如下所示:
@foreach (var service in Model)
{
    @Html.HiddenFor(m => service.ServiceID)
}

将产生一个名称为 service.ServiceID 的字段. modelbinder 不知道这个值应该去哪里并且基本上会忽略它。相反,您需要执行以下操作:
@for (var i = 0; i < Model.Count(); i++)
{
    @Html.HiddenFor(m => m[i].ServiceID)
}

这会让你的字段名称像 [0].ServiceID .同样,前缀是一个问题,因此您需要两个组件才能使其正常工作。

关于asp.net-mvc - 通过 AJAX 加载后,部分 View 的 View 模型未绑定(bind)到主视图模型的 View 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26980907/

相关文章:

c# - 我如何根据一天中的时间或访问者的设备等规则更改 Orchard CMS 中站点的主页?

asp.net-mvc - 如何在View中获取当前url值

asp.net - 环境标签助手

c# - 菜单控件 CSS 在 UpdatePanel 内时中断

asp.net-mvc - 在 Asp.net Core Identity 中通过电话号码注册并登录

c# - asp.net mvc Azure 云服务,我应该使用 TempData 还是 Sessions 来保存一些用户信息或其他信息

asp.net - ASP.NET Rich UI-您使用什么?

c# - "Invalid Character in Base-64 String"使用 ASP.NET 和 C#

javascript - 如何在另一个函数中获取 $.each 函数值

javascript - $.parseJSON(data, true) 抛出