加入相关的实体与ASP.NET MVC和剃刀? [英] Add related entities with ASP.NET MVC and Razor?

查看:75
本文介绍了加入相关的实体与ASP.NET MVC和剃刀?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有了一个导航属性​​的ICollection<地址>地址。在地址实体有一个属性城市

I have a Person class that has a navigation property ICollection<Address> Addresses. The Address entity has a property City.

我想给用户一个选项来创建/更新连同它的地址,包括添加和删除的。

I want to give the user an option to create/update a Person along with its addresses, including adding and removing ones.

因此​​,对于显示的地址我只需拨打 @ Html.EditorFor(M = GT; m.Addresses),和剃刀引擎使用我的自定义需要收集的护理驻留在模板中的 EditorTemplates 的文件夹中,产生的foreach场匹配的签名像 ID =Addresses_0__CityNAME =地址[0]。城市 。结果
到目前为止好。

So for displaying the addresses I simply call @Html.EditorFor(m => m.Addresses), and the razor engine takes care of the collection using my custom template that resides in the EditorTemplates folder, generating foreach field a matching signature like id="Addresses_0__City" name="Addresses[0].City".
So far so good.

的问题是添加新的地址上课。结果
我创建了一个按钮,单击时,一个jQuery函数调用一个动作(这是通过自定义的 EditorTemplate 的渲染),但其字段没有如上面签名,但只是 ID =城NAME =城市,因此,在后动作不公认的实体的一部分。

The problem is adding new Addresses.
I created a button that when clicked, a jQuery function calls an action (that's rendered via the custom EditorTemplate), but its fields don't have that signature as above, but just id="City" name="City", and thus, isn't recognized in the post action as part of the Person entity.

我怎么有那些 ID 名称与正确的签名生成的字段?

How do I have those id and name fields generated with the correct signature?

我读过的文章和许多其他人,但没有找到该地址的 ID 名称取值问题。

I've read this article and many others, but found none that address the ids and names issue.

推荐答案

我最终使用以下按上的意见建议。

I ended up using the following as per the suggestions on comments.

反正它困扰着我,我有包装的新项目作为收藏,并隐藏字段是集项目后仅追加,而不是被注入(因为它去除停留在那里)。

Anyway it bothered me that I have to wrap the new item as collection, and that the hidden field is just appended after the collection item, rather than being injected to (because at removal it stays there).

所以,我最终加入以下扩展剃刀上的要使用两个CSHTML 的文件,并加入新的项目到集合时就是所谓的行动:

So I ended up adding the following extensions to be used both on the Razor cshtml files, and on the action that's called when adding a new item to the collection:

下面是扩展名(也有一些更多的重载,请参阅完整code rel=\"nofollow\">):

Here are the extensions (there are some more overloads, please see the full code here):

private static string EditorForManyInternal<TModel, TValue>(HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TValue>>> expression, IEnumerable<TValue> collection, string templateName)
{
  var sb = new StringBuilder();

  var prefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
  var htmlFieldName = (prefix.Length > 0 ? (prefix + ".") : String.Empty) + ExpressionHelper.GetExpressionText(expression);

  var items = collection ?? expression.Compile()(html.ViewData.Model);
  foreach (var item in items)
  {
    var guid = Guid.NewGuid().ToString();

    var dummy = new { Item = item };
    var memberExp = Expression.MakeMemberAccess(Expression.Constant(dummy), dummy.GetType().GetProperty("Item"));
    var singleItemExp = Expression.Lambda<Func<TModel, TValue>>(memberExp, expression.Parameters);

    var editor = html.EditorFor(singleItemExp, templateName, string.Format("{0}[{1}]", htmlFieldName, guid));
    var hidden = String.Format(@"<input type='hidden' name='{0}.Index' value='{1}' />", htmlFieldName, guid);

    var eNode = HtmlNode.CreateNode(editor.ToHtmlString().Trim());
    if (eNode is HtmlTextNode)
      throw new InvalidOperationException("Unsuported element.");

    if (eNode.GetAttributeValue("id", "") == "")
      eNode.SetAttributeValue("id", guid);

    var hNode = HtmlNode.CreateNode(hidden);
    eNode.AppendChild(hNode);
    sb.Append(eNode.OuterHtml);
  }

  return sb.ToString();
}

public static MvcHtmlString EditorForMany<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, IEnumerable<TValue>>> expression, string templateName)
{
  var value = EditorForManyInternal(html, expression, null, templateName);
  return new MvcHtmlString(value);
}

在视图用法:

<div>
  <h4>@Resources.Person.Children</h4>
  <ul id="patientChildren" class="list-group ajax-collection">
    @Html.EditorForMany(m => m.Children)
  </ul>

  @Ajax.ActionLink("Create Child", "CreateChild", new { patientId = Model.Id, lastName = Model.LastName }, new AjaxOptions { UpdateTargetId = "patientChildren", InsertionMode = InsertionMode.InsertAfter, OnSuccess = CommonData.AjaxOnSuccessJsFuncName }, new { @class = "button btn-default" })
</div>

下面是被调用的AJAX功能(它与 Ajax的集合项目并有一个删除按钮归类 BTN归类生成的项目是非常重要的删除

Here's the ajax function being called (it's important to have the generated items classed with ajax-collection-item and have a remove button classed btn remove):

//#region Ajax add and remove
var ajaxCollectionItemSelector = '.ajax-collection-item';
function attachAjaxRemoveHandlers(id) {
  var context = $(id ? '#' + id : ajaxCollectionItemSelector);

  var removeButton = context.find('.btn.remove');

  removeButton.click(function () {
    var button = $(this);
    var collectionItem = button.closest(ajaxCollectionItemSelector);
    collectionItem.remove();
  });
};

function ajaxOnSuccess(ajaxContext) {
  var collectionItem = $(ajaxContext);
  var id = collectionItem.prop('id');
  attachAjaxRemoveHandlers(id);
  //TODO: following line doesn't work
  collectionItem.find(':text:first-of-type').focus();
};

function runCommonScripts() {
  attachAjaxRemoveHandlers();
};
//#endregion Ajax add and remove

新项目的动作(拥有CreateChild ),如下所示(在 EditorForSingle 分机上的同一个地方

The new item action (CreateChild) looks like the following (the EditorForSingle extension is on the same place:

public ContentResult CreateChild(int patientId, string lastName)
{
  return this.EditorForSingle((Patient p) => p.Children, 
    new PatientChild
    { 
      PatientId = patientId, 
      LastName = lastName 
    });
}

这篇关于加入相关的实体与ASP.NET MVC和剃刀?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆