我使用Razor为我的MVC应用程序编辑了一个页面.
我有一个像这样的模型:
public class MyModelObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<MyOtherModelObject> OtherModelObjects { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
而MyOtherModelObject看起来像:
public class MyOtherModelObject
{
public string Name { get; set; }
public string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我正在为MyModelObject制作编辑页面.我需要一种方法在MyModelObject的Edit页面上为表单添加空间,以便用户创建/添加尽可能多的MyOtherModelObject实例,因为用户希望使用List of OtherModelObjects.
我认为用户可以点击一个按钮,该按钮将执行ajax到另一个动作,该动作返回表单元素的PartialView(没有表单标签,因为这是我的编辑页面上的部分表单).当用户添加了他们想要的所有MyOtherModelObject并填写了数据时,他们应该能够将他们的编辑保存到现有的MyModelObject,这将HttpPost保存到Edit操作,并希望所有MyOtherModelObjects都在正确的列表中.
我还需要用户能够在添加项目后重新订购这些项目.
有谁知道如何使这项工作?是否实施了此解决方案的示例项目或在线示例演练?
Dar*_*rov 19
此博客文章包含一个分步指南,说明如何实现这一目标.
更新:
根据评论部分的要求,我将逐步说明如何使上述文章适应您的方案.
模型:
public class MyOtherModelObject
{
public string Name { get; set; }
public string Description { get; set; }
}
public class MyModelObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<MyOtherModelObject> OtherModelObjects { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
控制器:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyModelObject
{
Id = 1,
Name = "the model",
Description = "some desc",
OtherModelObjects = new[]
{
new MyOtherModelObject { Name = "foo", Description = "foo desc" },
new MyOtherModelObject { Name = "bar", Description = "bar desc" },
}.ToList()
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyModelObject model)
{
return Content("Thank you for submitting the form");
}
public ActionResult BlankEditorRow()
{
return PartialView("EditorRow", new MyOtherModelObject());
}
}
Run Code Online (Sandbox Code Playgroud)
查看(~/Views/Home/Index.cshtml):
@model MyModelObject
@using(Html.BeginForm())
{
@Html.HiddenFor(x => x.Id)
<div>
@Html.LabelFor(x => x.Name)
@Html.EditorFor(x => x.Name)
</div>
<div>
@Html.LabelFor(x => x.Description)
@Html.TextBoxFor(x => x.Description)
</div>
<hr/>
<div id="editorRows">
@foreach (var item in Model.OtherModelObjects)
{
@Html.Partial("EditorRow", item);
}
</div>
@Html.ActionLink("Add another...", "BlankEditorRow", null, new { id = "addItem" })
<input type="submit" value="Finished" />
}
Run Code Online (Sandbox Code Playgroud)
部分(~/Views/Home/EditorRow.cshtml):
@model MyOtherModelObject
<div class="editorRow">
@using (Html.BeginCollectionItem("OtherModelObjects"))
{
<div>
@Html.LabelFor(x => x.Name)
@Html.EditorFor(x => x.Name)
</div>
<div>
@Html.LabelFor(x => x.Description)
@Html.EditorFor(x => x.Description)
</div>
<a href="#" class="deleteRow">delete</a>
}
</div>
Run Code Online (Sandbox Code Playgroud)
脚本:
$('#addItem').click(function () {
$.ajax({
url: this.href,
cache: false,
success: function (html) {
$('#editorRows').append(html);
}
});
return false;
});
$('a.deleteRow').live('click', function () {
$(this).parents('div.editorRow:first').remove();
return false;
});
Run Code Online (Sandbox Code Playgroud)
备注:BeginCollectionItem自定义帮助程序取自我链接到的同一篇文章,但为了完整起见,我在这里提供它:
public static class HtmlPrefixScopeExtensions
{
private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";
public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
{
var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();
// autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));
return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
}
public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
{
return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}
private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
{
// We need to use the same sequence of IDs following a server-side validation failure,
// otherwise the framework won't render the validation error messages next to each item.
string key = idsToReuseKey + collectionName;
var queue = (Queue<string>)httpContext.Items[key];
if (queue == null)
{
httpContext.Items[key] = queue = new Queue<string>();
var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
if (!string.IsNullOrEmpty(previouslyUsedIds))
foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
queue.Enqueue(previouslyUsedId);
}
return queue;
}
private class HtmlFieldPrefixScope : IDisposable
{
private readonly TemplateInfo templateInfo;
private readonly string previousHtmlFieldPrefix;
public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
{
this.templateInfo = templateInfo;
previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
}
public void Dispose()
{
templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10738 次 |
| 最近记录: |