2013-07-12 10 views
5

私はCategoryModelというクラスを持っていますが、そのプロパティの1つは同じタイプのオブジェクトのリストです。したがってCategoryModel.CategoriesList<CategoryModel>です。MVCエディタ1つのページに複数の編集フォームをモデルバインドする

カテゴリインデックスページでは、各カテゴリのエディタを表示して、専用のページに移動しなくてもカテゴリ名を変更できるようにしました。これと同じように:

CategoryModelため
<ul id="categories> 
    @Html.EditorFor(model => model.Categories) 
</ul> 

、エディタのテンプレートは次のようになります。

<li class="folder"> 
    @using (Html.BeginForm("Edit", "Category", new { id = Model.Key }, FormMethod.Post, new { @class = "ajaxoff"})) { 
     @Html.ValidationSummary(true) 
     @Html.HiddenFor(model => model.Key) 
     @Html.HiddenFor(model => model.ParentKey) 
     @Html.HiddenFor(model => model.Sequence) 
     @Html.HiddenFor(model => model.IncludeDeleted) 

     @Html.TextBoxFor(model => model.Name, null, new { @class = "catName" }) 
     @Html.ValidationMessageFor(model => model.Name) 

     <input type="submit" value="Save" class="icon save" /> 
    } 
</li> 

私が持っている問題は、フォームを送信すると、CategoryControllerEditアクションに正しく結合しないということです。

[HttpPost] 
public ActionResult Edit(CategoryModel category) 
{ 
    // At this point all properties in category are null 
} 

隠しフィールドとテキストボックスの名前を確認すると、現在のカテゴリの位置に基づいてラベルが付けられますory(例えば、 Categories[0].Name)。ただし、専用の編集ビューを作成した場合、フィールド名に基づいて名前が付けられます(例:Name)。

私は、カテゴリーのリストを受け入れるようにコントローラを変更しようとしている:

[HttpPost] 
public ActionResult Edit(List<CategoryModel> categories) 
{ 
    var category = categories.First(); 
} 

私は非常に最初のカテゴリを提出する場合、これは動作しますが、他のどれも(これらの例でCategoriesがnullではありません)。

私も、私はこれを行うことによって、私のEditorForの表示方法を変更しようとしている:

<ul id="categories> 
    @foreach (var cat in Model.Categories) 
    { 
     @Html.EditorFor(model => cat); 
    } 
</ul> 

(例えば、すべてのカテゴリ名がcat.Nameと呼ばれている)、カテゴリごとに同じになるようにフィールド名を変更する、その私が信じることは正しい方向への一歩です。

コントローラに正しくバインドするにはどうすればよいですか?親カテゴリー全体をサブミットしてから各サブカテゴリーを保存することができますが、これは単一の変更をサブミットするのは非常に非効率的な方法です。

答えて

6

public class BeginHtmlScope : IDisposable 
    { 
     private readonly TemplateInfo templateInfo; 
     private readonly string previousHtmlFieldPrefix; 

     public BeginHtmlScope(TemplateInfo templateInfo, string htmlFieldPrefix) 
     { 
      this.templateInfo = templateInfo; 

      previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix; 
      templateInfo.HtmlFieldPrefix = htmlFieldPrefix; 
     } 

     public void Dispose() 
     { 
      templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix; 

     } 
    } 
    public static class MyHtmlExtensions 
    { 
     public static IDisposable BeginHtmlScope(this HtmlHelper html, string htmlFieldPrefix) 
     { 
      return new BeginHtmlScope(html.ViewData.TemplateInfo, htmlFieldPrefix); 
     } 
    } 

そして、あなたのエディタのテンプレート内でそれを使用します。このためには、このようにHtmlHelperのための独自の拡張メソッドを作成する必要があります。

@foreach (var cat in Model.Categories) 
{ 
    @Html.EditorFor(model => cat, null, ""); 
} 

これは、任意のプレフィックスなしのフィールド名のすべてをレンダリングし、私は成功した任意の単一のカテゴリを提出することができます:あなたは(下の例では三番目のパラメータ)htmlFieldNameプロパティを指定することができますHtml.EditorForためのオーバーロードがあります。

+1

私はこれをしましたが、フィールド名の後に[0]と[1]が得られます。どうしましたか? – Dennis

+1

あなたが説明した問題は発生しませんでした。上記のループの代わりに@ Html.EditorFor(model => model.Categories、null、 "")を使用した場合、フィールド名の前に[0]と[1]が得られます。個々のモデルの代わりにEditorForメソッドを使用します。 – Maloric

0

あなたの編集アクションはCategoryModelカテゴリを受け入れますので、右バインディングのモデル接頭辞をリセットする必要があります。私はこれを行う方法を発見

@using (Html.BeginHtmlScope("")) 
{ 
    <li class="folder"> 
    @using (Html.BeginForm("Edit", "Category", new { id = Model.Key }, FormMethod.Post, new { @class = "ajaxoff"})) { 
     @Html.ValidationSummary(true) 
     @Html.HiddenFor(model => model.Key) 
     @Html.HiddenFor(model => model.ParentKey) 
     @Html.HiddenFor(model => model.Sequence) 
     @Html.HiddenFor(model => model.IncludeDeleted) 

     @Html.TextBoxFor(model => model.Name, null, new { @class = "catName" }) 
     @Html.ValidationMessageFor(model => model.Name) 

     <input type="submit" value="Save" class="icon save" /> 
    } 
</li> 

} 
+0

残念ながら、これはforeachループと同じ問題があります。フィールド名はCategories [0] .Name、Categories [1] .Nameなどであり、CategoryModelはEditアクションにバインドしません。 – Maloric

+0

あなたの質問を誤解して申し訳ありません。私は私の答えを編集しました。 –

関連する問題