【问题标题】:How to preserve cascading dropdownlist items after httppost if form has invalid ModelState如果表单具有无效的 ModelState,如何在 httppost 之后保留级联下拉列表项
【发布时间】:2016-01-02 04:42:24
【问题描述】:

我在一个视图中有三个下拉菜单(级联)。第一个下拉元素来自 ViewModel。当第一个下拉列表更改时,我正在填充第二个下拉元素。和第三个下拉菜单一样。您可以在任何地方找到经典的级联下拉列表示例(例如:http://www.c-sharpcorner.com/UploadFile/4d9083/creating-simple-cascading-dropdownlist-in-mvc-4-using-razor/

用户提交表单时出现问题。如果 ModelState 无效,则第 2 和第 3 个下拉菜单会丢失其项目,第 1 个下拉菜单会保留其状态。我理解他们为什么会这样,但不知道如何用用户选择的值再次填充它们。

场景

  1. 用户请求/Country/Index
  2. page loaded之后,用户选择CountryId DropDownList
    • Country Id 发送到方法,如果结果不为空,则加载StateId DropDownList
  3. 请勿填写PostalCode Textbox 并提交表单。
  4. 检查 CountryId DropDownlist 是否已填充并选中,但 StateId ropdownlist 为空。
  5. 哭泣

查看

//HTML Code
//...

@Html.DropDownListFor(m => m.CountryId, ViewBag.Country as IEnumerable<SelectListItem>, "Select Country")
@Html.DropDownListFor(m => m.StateId, new SelectList(string.Empty, "Value", "Text"), "Select State")
@Html.DropDownListFor(m => m.CityId, new SelectList(string.Empty, "Value", "Text"), "Select City")
@Html.TextBoxFor(m=> m.PostalCode)

<script type="text/javascript">
var countryDDL = $("#CountryId");
countryDDL.change(function () {
                $.ajax({
                    type: 'POST',
                    url: '@Url.Action("LoadStateList")',
                    dataType: 'json',
                    data: { countryId: countryDDL.val() },
                    success: function myfunction(states) {
                        $("#StateId").empty();
                        $.each(states, function (i, state) {
                            $("#StateId").append('<option value="' + state.Value + '">' + state.Text + '</option>');
                        }); }
                   });
                   return false;
                });

//Code for 2nd (state) dropdownlist.change() method.
//...
</script>

控制器

public ActionResult Index()
{
    ViewBag.CountryList = LoadCountryList();
    return View();
}

[HttpPost]
public ActionResult Index(CountryViewModel cvm)
{
    if(ModelState.IsValid)
    {
        //Save or do whatever you want
    }

    ViewBag.CountryList = LoadCountryList();
    return View();
}

查看模型

public class CountryViewModel
{
    public int CountryId {get;set;}
    public int StateId {get;set;}
    public int CityId {get;set;}

    [Required]
    public string PostalCode {get;set;}
}

【问题讨论】:

  • 再次将模型传递回视图(在发布时处于无效状态),并在渲染 select 时确保所选项目具有他们在将其提交到之前选择的 id服务器。
  • 您的意思是再次在 HttpPost 方法中使用 CountryId 获取状态并发送回查看?如果是这样,这意味着我需要在 ViewBag.StateList 中发送具有初始值的 StateList 并更改 StateDDL 代码,例如使用 ViewBag.StateList 的 CountryDDL?合理。
  • 我想你可能想多了(或者我错过了一些基本的东西)。难道你不需要将cvm 传递给View() 吗?
  • 查看this DotNetFiddle中的代码——尤其是控制器代码。

标签: c# jquery model-view-controller drop-down-menu asp.net-mvc-5


【解决方案1】:

实际选择选项未发布(也不应该发布)。因此,当您执行 post 操作时,您的选择列表为空。解决方案?只需像在 get 操作中一样重新填充它。当然,在这里,您不是在 get 操作中填充它们,而是通过 AJAX 检索它们。如果您愿意,您可以在技术上以同样的方式在帖子中执行此操作。您只需在页面加载时运行 AJAX 调用即可重新获取选择列表。但是,此时最好在您的发布操作中执行此操作。

【讨论】:

  • 在控制器中填充看起来是一种更好的方法。我是一个老 ASP.NET 开发人员,每次都在填充下拉列表(以及其他控件,因为 mvc 是无状态的)只是困扰我,但没有其他方法哈!也许我可以将 ddl 项目存储在 Session 中,而不是每次都查询数据库?
  • 这就是我一直抱怨的 Web 表单的隐患:它向开发人员隐藏了幕后发生的事情。必须始终进行重新填充,Web 窗体或 MVC。只是,在 MVC 中,您要对它负责,而不是由 Microsoft 决定应该如何为您完成。
  • 但这会使数据库过载。大多数情况下,EntityFramework 一遍又一遍地使用和进行查询,这有点烦人。或许您可以说“Entity Framework 和 SQL 可以处理这些查询,技术得到改进”。您对让他们参与会议有何看法?
  • 如果您正确地进行会话,您仍然会访问数据库。但是,它几乎不会“重载”数据库来重新填充选择列表项。首先,Entity Framework 确实使用了查询缓存,因此它甚至可能不会再次访问数据库。其次,除非你正在做某种疯狂的查询,否则它会很快。数据库旨在快速有效地查询数据,除非您故意做低效和缓慢的事情。快速分析一下可以指出任何潜在的问题。
  • 总而言之,如果您有一个好的优化查询,并且 单独 能够使您的数据库超载,那么您有一些严重的问题需要解决固定的。也许数据库需要更多资源。无论如何,如果您真的担心,您可以使用 ASP.NET 提供的内置内存缓存将查询结果缓存一段时间,然后首先尝试从中提取项目在使用 EF 之前缓存。也就是说,您的应用程序中可能有 100 个不同的区域需要优化,然后才能进行类似的操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多