【问题标题】:Persisting data from multiple forms in ASP.NET MVC在 ASP.NET MVC 中持久化来自多个表单的数据
【发布时间】:2009-06-14 19:45:58
【问题描述】:

我在一个页面上有两个表单:一个结果表单和一个搜索表单。搜索表单使用局部视图,因为它显示在几个不同的页面上。无论用户单击哪个表单上的哪个按钮,我都希望能够将数据保留在搜索表单中。问题是当用户点击结果表单中的链接或按钮时,只会发布结果表单中的表单值,而不包括搜索表单中的值。即使不是提交的表单,我如何维护搜索表单中的值?我不想使用任何类型的会话状态来维护表单,也不想在结果表单的隐藏字段中写入搜索值。我只是希望能够将它们与结果表单的表单值一起发布,以便可以在显示搜索部分视图的任何页面上维护用户搜索条件。我错过了什么?

我的第一个想法是删除包装搜索控件的表单,并让它与结果数据一起呈现到表单中。我在这里担心命名冲突。当搜索来自与结果表单同名的控件时会发生什么,这不会导致命名冲突吗?我想这可以手动管理,以确保在将部分视图渲染到其他视图时有唯一的名称,甚至可以用部分视图名称作为前缀值,但这让我想起了 INamingContainer 中的丑陋Web 表单 - 再加上模型中的繁琐字段名称。

是否有某种优雅的解决方案可以让表单保持我丢失的状态?谢谢!

【问题讨论】:

  • 好吧,如果你想一次性提交它,你需要一个覆盖结果表单和搜索表单的
    标签。如果你这样做,你基本上会得到 ASP.NET Web 表单;)它甚至可以很好地处理命名冲突......
  • 哈哈哈...我遇到了同样的问题。一定要收藏这个。

标签: asp.net-mvc


【解决方案1】:

通常,在执行搜索时,我会在服务器端保留搜索条件。如果用户在执行搜索后更改了搜索条件,然后发布表单,任何更改当然都会丢失,但由于没有调用搜索,这可以说是正确的行为。无论是从完整帖子还是通过 ajax 执行搜索,都是如此。以这种方式处理它可以使操作更清晰,我认为您不需要在其他操作中处理搜索数据。

如果您绝对需要包含搜索参数,您可以考虑通过 javascript 发布第二个表单,在发布第二个表单之前动态获取搜索字段值并将它们添加到第二个表单(作为隐藏字段) .您不必同步维护两个位置的值,但必须在发布之前将它们复制到第二个表单。

【讨论】:

  • 感谢您的输入,我已经想到了 javascript 选项,但我试图避免依赖客户端脚本。我想我倾向于你的第一个选项,虽然我不愿意依赖服务器端会话状态,但我什至考虑过使用查询字符串,但是从一个页面到另一个页面的推送太多了。我还考虑过 base64 编码搜索控件的表单值并将它们填充到另一个表单上的隐藏变量中,也许称之为 ViewState ......哦,等等,这已经完成了......但真的会太邪恶吗?
  • 伙计,不要害怕客户端。如果使用得当,它会大大简化开发 + 使用户体验更好。
  • 经过深思熟虑并查看了可能的解决方案后,我们决定保留搜索条件服务器端,因此我将您的答案标记为正确。谢谢。
【解决方案2】:

目前我是这样理解的:

具有搜索框的表单,将查询(以及需要的其他数据)发布到搜索控制器,然后呈现搜索视图。搜索视图由搜索框和搜索结果部分视图组成。在此期间 - 搜索框表单由发布的数据重建。

如果我需要搜索结果表单来执行另一个搜索请求(例如,使用指定的页面索引),它会通过 ajax,它从搜索结果表单中发布搜索框表单 + 页面索引。查看here 的想法(使用 targetId 参数更新该 JS 方法以更新指定的 div/form 并在需要时在此处发布其他数据,如下所示:

form.serialize()+"&pageIndex=5"

简而言之:如果您需要维护表单状态 + 在一个页面中更新另一个 - 考虑使用部分更新,否则您最终会发明 ViewState 2.0。

这种方式的一个警告 - 让搜索框包含与搜索结果相关的内容(即 - 找到的项目的总数)是很棘手的。在我设法处理这个问题之前,我们的设计师已经这样做了——我只需要添加具有适当类名(“sbsubst”或其他名称)的 div,它看起来就在搜索框内。 :)

【讨论】:

  • “否则你最终会发明 ViewState 2.0”——完全同意 :)
  • 另一方面 - 这一点都不好......搜索请求必须是 RESTful - 他们必须使用 GET 方法。这导致使用 $("#searchbox").serialize()+"&page=3" 在搜索结果页面中创建 URL,并通过提交(通过查询)值重建搜索框。
【解决方案3】:

当页面上的表单很少时,每个表单只发送自己的数据。在 WebForms 中,您只有一个表单(至少是服务器端的),并且每个控件都包含在此表单中。在 ASP.NET MVC 中,您可以使用相同的场景,如果您想拥有所描述的行为,恐怕您将不得不这样做。不要忘记 - 部分形式不必是真实形式。此外,RenderPartial 主要用于“类似控件”的布局创建。

至于您问题的第二部分,我建议您在搜索表单中使用一些正常的前缀(如“搜索”或类似的前缀)命名您的文本框。例如,如果表单中有文本框“text”和“language”,则将有“searchText”和“searchLanguage”。这些名称非常独特,您将在参数中使用正常名称。

我不建议您在 POST 事件中填充结果表单中的隐藏值,因为您说这不是您的选择,但如果您想拥有两个表单,它仍然可能是唯一的方法。

【讨论】:

  • 我使用局部视图来保持它干燥,因为搜索表单几乎在应用程序的每个页面上。如上所述,我不想为每个字段添加前缀,因为它看起来既麻烦又错误,而且搜索模型名称与底层数据库架构不匹配。这对我来说是不是太挑剔了?可能。现在,我只是在探索我的选择,然后再致力于一个架构并将自己编码到一个角落。感谢您的输入
【解决方案4】:

我认为最好的方法是在您的第二个表单操作 url 的查询部分发生更改时存储来自搜索输入的文本。例如(未测试):

$('input#yourSearchInput').change(function()
{
    var searchText = $(this).val();

    // or? var searchText = encodeURIComponent($(this).val());

    var secondForm = $('form#secondFormId');

    var action = secondForm.attr('action');

    var queryStart = action.lastIndexOf('?search=');
    if(queryStart > -1) {
        action = action.substring(1, queryStart);
    }

    action = action + "?search=" + searchText;

    secondForm.attr('action', action);
});

在控制器(或自定义过滤器)中:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var search = Request.QueryString["search"];
    if(!String.IsNullOrEmpty(search)) {
        ViewData["SearchFromPOST"] = search;
    }
    base.OnActionExecuting(filterContext);
}

在您的搜索控件中:

<%= TextBox("yourSearchInputId", ViewData["SearchFromPOST"]) %>

【讨论】:

  • 感谢您的意见和想法。但是,我们正在处理可能允许也可能不允许客户端脚本的银行客户,因此这对我们来说不是一个好的选择。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多