2012-12-26 112 views
4

我有一个MVC 3页面,该页面返回用户响应列表,其中包含每个响应的称为“备忘录”(显示/添加备忘录)的局部视图。当我将备忘录添加到响应时,它应该更新该响应的db和备忘录列表。它应该通过ajax进行局部页面更新,这只会影响部分视图“备忘录”。仅更新mvc 3页面中包含的部分视图?

包含 “备忘录” 的视图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" [email protected] 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的表单动作冲突吗?

回答

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

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

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

当AJAX调用成功,它将接收该部分从所述控制器的操作方法叫回去。然后它将部分和附加到能力表体

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

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

+0

谢谢你的例子和详细的解释。 – Chaka

+0

我很高兴能够提供帮助。 –

1

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

查看here,特别是在“加载页面片段”部分。基本上,您可以再次获取原始页面,只要jQuery能够通过选择器(例如div id)对其进行定位,jQuery就会“提取”您想要的内容。

注意,这解决方案并不适用于所有情况一样会有来自服务器的响应多余的标记,因为你会被丢弃页面内容的其余部分,只是使用更新的一部分。

相关问题