4

我有一个MVC 3页面,它返回一个用户响应列表,每个响应都有一个名为“备忘录”的部分视图(显示/添加备忘录)。当我向响应添加备忘录时,它应该更新数据库和该响应的备忘录列表。它应该是通过 ajax 进行的部分页面更新,它只影响部分视图“备忘录”。

包含“备忘录”的视图 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 调用成功后,如何更新列表备忘录div="memos"以反映新的备忘录?

  3. Response中的表单动作会和部分视图Memo的表单动作冲突吗?

4

2 回答 2

2

问题的答案:

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

这是我目前正在从事的一个项目的修改示例:

有一些代码要遵循,所以这里是:

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

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>
}

视图/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);

我希望这有帮助。如果您有任何其他问题,请告诉我。

于 2012-12-28T13:14:16.040 回答
1

虽然您可以通过返回包含更新内容的局部视图来做到这一点是正确的,但您也可以考虑使用 jQuery 的 load 方法。

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

请注意,此解决方案并非在所有情况下都适用,因为服务器的响应中会有多余的标记,因为您将丢弃页面内容的其余部分并仅使用更新的部分。

于 2012-12-26T18:26:09.173 回答