【问题标题】:Updating only the partial view contained in a mvc 3 page?仅更新 mvc 3 页面中包含的部分视图?
【发布时间】:2012-12-26 03:02:08
【问题描述】:

我有一个 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的表单动作冲突吗?

【问题讨论】:

    标签: ajax asp.net-mvc sql-update partial-views


    【解决方案1】:

    问题解答:

    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);
    

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

    【讨论】:

    • 感谢您的示例和详细说明。
    • 很高兴能帮上忙。
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-04-09
      • 2012-12-02
      • 2012-10-24
      • 1970-01-01
      • 2017-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多