更新仅包含在MVC 3页面中的部分视图?

4
我有一个返回用户响应列表的MVC 3页面,每个响应都有一个名为“memo”的局部视图(用于显示/添加备忘录)。当我向响应中添加备忘录时,它应该更新数据库和该响应的备忘录列表。应该通过ajax进行局部页面更新,仅影响局部视图“memo”。
包含“memo”的视图Response.chtml:
@using (Html.BeginForm("Response", "User", FormMethod.Post, new { id = "UserResponse" }))
   {
      .... code removed ....
@foreach (var response in Model)
                {
                <div class="qna"><input type="text" id=@response.responseId value="@response.ResponseText" />  

                 <div>@Html.Partial("_memo", response.responseId)</div>
                }
        .....

"_memo.chtml" 部分页面:


<div>add memo</div> 

<ul id="memos">                                          
@foreach (var memo in Model) {                           
    <li>@memo.Text</li>                                       
}                                                           
</ul>                                                       

<form method="post" id="memoForm"                        
      action="@Url.Action("AddMemo")">                   

    @Html.TextArea("Memo", new { rows = 5, cols = 50 })   
    <br />
    <input type="submit" value="Add" />
</form> 

用户/响应视图的控制器:

[HttpGet]
        public ActionResult Response(id)
        {
           .....
            return View(responses);

我刚刚开始使用上面的代码,需要帮助填写空白部分。

  1. 如果我将响应ID传递给局部视图,如何获取该响应的备忘录列表?这是否涉及到ajax?(而不是.. Partial("_memo", response.memos)

  2. 通过ajax调用如何更新局部视图。客户端的ajax调用(示例代码)是什么样子的,控制器会怎样呢?当ajax调用成功时,如何更新备忘录列表以反映新的备忘录?

  3. 响应的表单操作是否会与局部视图Memo的表单操作冲突?

2个回答

2

问题解答:

  1. 您不应该将responseId传递给partial,而应该将来自响应对象的备忘录集合传递并使您的partial视图强类型化到该集合。
  2. 请参见下面的完整代码示例。
  3. 由于您正在进行简单的ajax调用以添加新备忘录,因此您不需要在partial中使用表单。请参见下面的完整代码示例。

这是我目前正在工作的项目的修改示例:

以下是一些代码:

这是我的模型。职业规划表上有几个部分,其中之一是选择和更新能力的部分。SelectCompetencies模型中包含了一组能力。用户将能够添加能力。当他们这样做时,它将被添加到数据库中,并将更新partial中的能力列表。

public class CareerPlanningFormViewModel
{
    // code removed ...

    public SelectCompetenciesModel SelectCompetencies { get; set; }

    // code removed ...
}

public class SelectCompetenciesModel
{
    public int CareerPlanningFormID { get; set; }

    public IList<CompetencyModel> Competencies { get; set; }

    public byte MaximumCompetenciesAllowed { get; set; }
}

public class CompetencyModel
{
    public int CompetencyID { get; set; }

    public int? CompetencyOptionID { get; set; }

    public string ActionPlan { get; set; }

    public IDictionary<int, string> CompetencyOptions { get; set; }
}

职业规划表单的主视图:/Views/CPF/CareerPlanningForm.cshtml
@model MyNamespace.Models.CareerPlanningForm.CareerPlanningFormViewModel
<link rel="stylesheet" href="@Url.Content("~/Content/CreateCPF.css")" />
@using (Html.BeginForm())
{
    // other sections loaded here...
    // code removed for brevity...

    @Html.Partial("SelectCompetencies", Model.SelectCompetencies)

    // other sections loaded here...
    // code removed for brevity...
}

SelectCompetencies 部分视图:/Views/CPF/SelectCompetencies.cshtml 用户将填写新的行动计划文本并单击添加能力按钮。 这将通过 AJAX 发布到 CPFController/NewCompetencyTemplate。

@model MyNamespace.Models.CareerPlanningForm.SelectCompetenciesModel
@Html.HiddenFor(m => m.CareerPlanningFormID)
<h3>Select Competencies</h3>
<p class="guidance">
    Select up to @Model.MaximumCompetenciesAllowed competencies to focus on improving.
</p>
<table id="CompetenciesTable">
    <thead>
        <tr>
            <th>Competency</th>
            <th>Action Plan:</th>
        </tr>
    </thead>
    <tbody>
        @for (int i = 0; i < Model.Competencies.Count(); i++)
        {
            @Html.EditorFor(m => m.Competencies[i])
        }
    </tbody>
    <tfoot id="CompetenciesTableFooter" class="@(Model.Competencies.Count() < Model.MaximumCompetenciesAllowed ? "" : "hidden")">
        <tr>
            <td colspan="2">
                @Html.TextArea("NewActionPlanText")
                @Html.Button(ButtonType.Button, "Add Another Competency", "add", new { id = "AddCompetencyButton" })
            </td>
        </tr>
    </tfoot>
</table>
@section script
{
    <script>
        jQuery(document).ready(function ($) {

            var competenciesTableBody = $('#CompetenciesTable tbody'),
                competenciesTableFooter = $('#CompetenciesTableFooter'),
                addCompetencyButton = $('#AddCompetencyButton'),
                newCompetencyTemplateUrl = '@Url.Content("~/CPF/NewCompetencyTemplate")',
                count = competenciesTableBody.find('tr').length,
                newActionPlanText = $('#NewActionPlanText'),
                careerPlanningFormID = $('#CareerPlanningFormID');

            addCompetencyButton.click(function () {
                $.ajax({
                    url: newCompetencyTemplateUrl(),
                    type: 'POST',
                    data: {
                        careerPlanningFormID: careerPlanningFormID,
                        actionPlan: newActionPlanText,
                        itemCount: count
                    },
                    dataType: 'html',
                    success: function (data) {
                        var elements = $(data);

                        // other code removed here...

                        competenciesTableBody.append(elements);

                        // other code removed here...
                    }
                });
            });    

        });
    </script>
}

Views/CPF/EditorTemplates/CompetencyModel.cshtml

@model MyNamespace.Models.CareerPlanningForm.CompetencyModel
<tr class="competency">
    <td>
        @Html.DropDownListFor(m => m.CompetencyOptionID, new SelectList(Model.CompetencyOptions, "Key", "Value"), "Select competency...")
    </td>
    <td>
        @Html.TextAreaFor(m => m.ActionPlan, new { @class = "competencyActionPlan" })
        @Html.HiddenFor(m => m.CompetencyID)
    </td>
</tr>

包含添加新能力的操作的控制器:/Controllers/CPFController.cs

这将调用CareerPlanningFormService来添加新能力,并返回一个部分视图NewCompetencyTemplate,以呈现新能力。

public class CPFController : Controller
{
    private readonly ICareerPlanningFormService careerPlanningFormService;

    public CPFController(ICareerPlanningFormService careerPlanningFormService)
    {
        this.careerPlanningFormService = careerPlanningFormService;
    }

    [HttpPost]
    public PartialViewResult NewCompetencyTemplate(int careerPlanningFormID, int itemCount, string newActionPlanText)
    {
        var count = itemCount + 1;

        // Even though we're only rendering a single item template, we use a list
        // to trick MVC into generating fields with correctly indexed name attributes
        // i.e. Competencies[1].ActionPlan
        var model = new SelectCompetenciesModel
        {
            Competencies = Enumerable.Repeat<CompetencyModel>(null, count).ToList()
        };

        model.Competencies[count - 1] = this.careerPlanningFormService.BuildNewCompetencyModel(careerPlanningFormID, newActionPlanText);

        return this.PartialView(model);
    }
}

我的服务类: CareerPlanningFormService.cs

该类处理业务逻辑并调用存储库将项目添加到数据库,并返回一个新的能力模型(CompetencyModel)

public class CareerPlanningFormService : ICareerPlanningFormService
{
    private readonly IMyRenamedRepository repository;
    private readonly IPrincipal currentUser;

    public CareerPlanningFormService(
        IMyRenamedRepository repository,
        IPrincipal currentUser)
    {
        this.repository = repository;
        this.currentUser = currentUser;
    }

    public CompetencyModel BuildNewCompetencyModel(int careerPlanningFormID, string newActionPlanText)
    {
        var competency = new Competency
        {
            CareerPlanningFormID = careerPlanningFormID,
            CompetencyOptionID = null,
            ActionPlan = newActionPlanText
        };

        this.repository.Add(competency);
        this.repository.Commit();

        return new CompetencyModel
        {
            CompetencyID = competency.CompetencyID,
            CompetencyOptionID = competency.CompetencyOptionID,
            ActionPlan = competency.ActionPlan,
            CompetencyOptions = this.GetCompetencyOptionsForCareerPlanningFormID(careerPlanningFormID)
        };
    }
}

现在,NewCompetencyTemplate的局部视图文件是:Views/CPF/NewCompetencyTemplate.cshtml

这非常简单,它只是渲染与上面相同的编辑器模板,用于集合中的最后一个能力(我们刚刚添加)。

@model MyNamespace.Models.CareerPlanningForm.SelectCompetenciesViewModel
@Html.EditorFor(m => m.Competencies[Model.Competencies.Count() - 1])

当ajax调用成功时,它将从所调用的控制器动作方法接收此部分。然后,它将取得的部分附加到能力表格主体中。

// snippet from ajax call above
competenciesTableBody.append(elements);

我希望这可以帮到你。如果你有任何其他问题,请告诉我。

感谢您的示例和详细的解释。 - Chaka
我很高兴能够帮助。 - M.Ob

1

虽然您是正确的,可以通过返回包含更新内容的部分视图来完成,但您也可以考虑使用jQuery的load方法。

请看这里,特别是“加载页面片段”部分。基本上,您只需再次获取原始页面,jQuery将“提取”您想要的内容,只要它可以被选择器(例如div id)定位。

请注意,这种解决方案并不适用于所有情况,因为响应中会有冗余标记,因为您将丢弃其余页面内容,仅使用更新的部分。


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