MVC部分视图问题

5

我对MVC非常陌生,正在尝试找出更好的方法。我有一个文本框供用户输入搜索内容,然后根据该搜索结果显示一些结果在搜索框下面。我试图避免在视图中编写太多代码逻辑,并想知道是否有更好的处理方式。这是我的现有代码,根据"Model.Results"的值,它将返回3个部分视图之一或一个按钮(如果其余逻辑通过):

@section CustomerPrefixInfo
{
    @if (Model.Results == PrefixSearch.SearchResults.CustomerFound)
    {
        @Html.Partial("_CustomerPrefixInfo")
    }
    @if (Model.Results == PrefixSearch.SearchResults.PrefixResultsFound)
    {
        @Html.Partial("_PrefixResults")
    }
    @if (Model.Results == PrefixSearch.SearchResults.AnimalsFound)
    {
        @Html.Partial("_AnimalSearchResults")
    }
    @if (Model.Results == PrefixSearch.SearchResults.ValidNewPrefix)
    {
        using (Html.BeginForm("Index", "PrefixManagement", new { prefix = Model.AnimalPrefix.Prefix, dbPrefix = Model.AnimalPrefix.DbPrefix }))
        {
            <fieldset>
                <input id="btnReservePrefix" type="submit" value="Reserve Prefix" />
            </fieldset>
        }
    }
}

我希望将这段代码放入控制器中,以便它只返回要显示的视图,然后在页面上显示该视图。经过一些研究,我认为可以使用Ajax.BeginForm,并将InsertionMode设置为InsertAfter来完成此操作:

@using (Ajax.BeginForm("GenericSearch", "Home", FormMethod.Post, new AjaxOptions { InsertionMode = InsertionMode.InsertAfter, UpdateTargetId = "searchResults" }))
{
    <fieldset>
        <input id="btnPrefixSearch" type="submit" value="Prefix Search/Validate"/>
        @Html.EditorFor(model => model.Input)
    </fieldset>
    <div id="searchResults">

    </div>
}

我的 GenericSearch 操作会使用 switch 语句来决定返回哪个局部视图:
public ActionResult GenericSearch(PrefixSearch prefixSearch)
{
    //some database logic here to get the results
    switch (prefixSearch.Results)
    {
        case PrefixSearch.SearchResults.CustomerFound:
            return PartialView("_CustomerPrefixInfo", prefixSearch);
        case PrefixSearch.SearchResults.PrefixResultsFound:
            return PartialView("_PrefixResults", prefixSearch);
        case PrefixSearch.SearchResults.AnimalsFound:
            return PartialView("_AnimalSearchResults", prefixSearch);
        default:
            return null;
     }
}

但是当我尝试这样做时,它会将部分视图放在一个新页面上。

这是我的其中一个部分视图(它们都与此基本相同)。

@model MVC_Test_Project.Models.PrefixSearch

@{
    ViewBag.Title = "PrefixResults";
 }

@{
    Layout = null;
 }
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.PrefixResults[0].Prefix)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.PrefixResults[0].CustomerCount)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.PrefixResults[0].Link)
        </th>
    </tr>

@foreach (var item in Model.PrefixResults)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Prefix)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.CustomerCount)
        </td>
        <td>
            <a href="@item.Link">edit</a>               
        </td>
    </tr>
}
 </table>

任何帮助都将不胜感激! 编辑:如果有人犯了和我一样愚蠢的错误,请注意确保在脚本之前调用您的捆绑包。
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
@Scripts.Render("~/bundles/bootstrap")
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.unobtrusive-ajax.min.js"></script>

当被建议使用这些行时,我添加了最后2行,但它们在我的捆绑包之上...因此,由于此原因,ajax无法工作。感谢所有人的帮助,现在一切都很好! --Joseph


你能展示一下你的Partial View代码吗?它应该在顶部包含“@{ Layout=null;}”,这是用来告诉它不要使用任何母版页。 - Ehsan Sajjad
请确保您的控制器中的Action方法上方有[HttpPost]属性。此外,如果您只是“搜索”结果,而不是实际“发布”任何内容,则建议使用GET请求(无需在Action方法上方添加属性),并将FormMethod更改为Get,或尝试在AjaxOptions中设置HttpMethod"GET" - Geoff James
只是为了明确当我尝试使用Ajax时发生了什么:它获取结果并将它们放在一个空白页面上,而不是将其添加到现有页面中。我尝试了Geoff的建议,得到了相同的结果。我想我只是不理解如何将数据返回到我已经存在的页面的某个部分。 - jpaugh78
我已经添加了一个解决你的Ajax问题的答案。请查看下面的答案——虽然我不完全确定为什么它被踩了。-.- - Geoff James
1
@jpaugh78 为什么要使用 AJAX 呢?它似乎并不能解决你的具体问题。虽然 AJAX 是很酷的技术,我也经常尝试你正在尝试的事情,但对于你的特定需求来说,它似乎有些过度了。 - Erik Philips
显示剩余7条评论
2个回答

2

确保在需要执行 Ajax 的页面的顶部引入 jQuery 和 jquery.unobtrusive-ajax.js(或 jquery.unobtrusive-ajax.min.js)。

如下所示:

<script src="~/scripts/jquery-1.x.x.js" />
<script src="~/scripts/jquery.unobtrusive-ajax.js" />

...
The rest of your page down here
...

这样可以使Partial的回发在页面中呈现,而不是每次重定向。

如果您没有jQuery文件,或者不确定如何包含它们,请查看这里:http://www.c-sharpcorner.com/UploadFile/4fcb5a/update-a-div-and-partial-view-using-ajax-beginform-on-form-s/ -这非常有用。

确保在web.config文件中启用了Unobtrusive JS。它们在<appsettings>节点中如下所示:

<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>

如果您正在使用验证 - 虽然我怀疑您是否在进行搜索,但请跟着我说 - 您可能还想包括jquery.validate.jsjquery.validate.unobtrusive.js。这可以允许客户端验证(在可能的情况下),从而使用户体验更加流畅。
注意:还有其他方法可以进行Ajax请求;例如在自己的JS脚本中创建它 - 这个示例是使用一个已经可用并且备受喜爱的库最简单的方法 :)
希望这可以帮助您!
编辑: 选择要返回的部分视图的switch可以仅从控制器内部完成。您可以从页面视图中删除逻辑。
然后,Ajax将负责替换您给Ajax.BeginForm助手的div ID的内容。
您可以完全替换搜索表单 - 使用其ID,或者更好的方法是 - 在页面中放置一个空的<div>容器,准备显示结果:
<div id="searchResults"></div>

Ajax会返回部分视图,并将内容放入您的searchResults div中。 编辑2 我注意到在你的Ajax.BeginFormAjaxOptions对象中,你缺少HttpMethod = "POST"AjaxOptions应该看起来像这样:
new AjaxOptions {
            HttpMethod = "POST",
            UpdateTargetId = "searchResults",
            InsertionMode = InsertionMode.Replace
}

1
这并没有回答如何切换逻辑的问题。无论HTML如何呈现,他仍然希望将逻辑从视图中分离出来。 - Erik Philips
如果你仔细阅读帖子,他已经将逻辑放在Action的代码中,并决定返回哪个部分视图... - Geoff James
我已经编辑了我的答案,以澄清逻辑可以在哪里以及如何从返回部分视图来显示它在页面上。 - Geoff James
1
很高兴听到你有所进展 :) 在AjaxOptions对象属性中,我总是使用一件事情,而你没有; 那就是 HttpMethod = "POST"。尝试添加它并让我知道你如何处理 - 不要将其与已经存在的FormMethod.Post混淆; 你可以留下那个... - Geoff James
1
不可能!这是一个容易犯的错误。总之,我在我的答案中进行了编辑以便更加清晰明了。祝你好运! :) - Geoff James
显示剩余2条评论

2
我想把这个放在控制器里,这样它只返回视图。
看起来非常简单:
视图模型:
public class MyModel
{
  public string PageToRender { get; set; }
}

控制器操作

public ActionResult DoLogic()
{
  //var Results = ?? as The ENum

  switch(Results)
  {
    PrefixSearch.SearchResults.CustomerFound:
      model.PageToRender = "_CustomerPrefixInfo";
    // etc etc
  }    

  return View(model);
}

视图:

 @{if (!string.IsNullOrEmpty(model.PageToRender))
   Html.RenderPartial(model.PageToRender);}

虽然我可能会装饰这个枚举:

public enum SearchResults
{
  [Display(Name="_CustomerPrefixInfo")]
  CustomerFound
}

然后就没有switch语句了,你只需要获取枚举值显示属性的名称值


我在您的回答下方留言解释了我的反对票。根据您的评论,我认为您对我的回答进行的反对票有些虚伪。 - Erik Philips
我已经编辑了我的答案,包括逻辑可以放置的位置 - 他已经提到他会将逻辑放在控制器中; 所以我假设这是他前进的方式,并且需要知道如何将结果解析到页面上的div中 - 如果你有点生气,对不起。 - Geoff James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接