2013-02-05 18 views
7

私はビューモデルを持っている魔女は反復アイテムを含んでいます。私はEditorFor()メソッドを使ってそれらを私のビューに配置します。MVC4 EditorForフィールドにラインアイテムを動的に追加する方法は?

ビュー:

@model Models.MyModel 

@using (Html.BeginForm(@Model.Action, @Model.Controller)) 
{ 
    <div class="section" id="Terms"> 
     @Html.EditorFor(m => m.Terms) 
    </div> 

    <input type="submit" value="Save" /> 
} 

モデル:

public class MyModel 
{ 
    public IEnumerable<Term> Terms { get; set; } 
} 

EditorTemplates \ Term.cshtml:

@model Models.Term 

@if (Model != null) 
{ 
    <fieldset> 
     <legend>Term</legend> 

     @Html.HiddenFor(model => model.TermID) 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Identifier) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Identifier) 
      @Html.ValidationMessageFor(model => model.Identifier) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.Description) 
     </div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Description) 
      @Html.ValidationMessageFor(model => model.Description) 
     </div> 

    </fieldset> 
} 

私はbにしたいです動的knockout.jsでこの例のように、ビューのリストから項目を削除するが、どのように私は自動IDのMVCは??作成し保存しない/追加できるE:

http://knockoutjs.com/examples/cartEditor.html

ここでは、このために私の要件:

  • は、新しい用語
  • を追加用語
  • を削除
  • を追加された新しい用語の景色を検証

私はSOに関する他の質問を読みましたが、私はこれに関する本当の決定的な答えは見つかりませんでした。 knockout.jsはこれを受け入れる方法ですか?ノックアウトとMVCでこれを行う例はありますか?

ありがとうございます!

答えて

0

あなたはこのためにノックアウトを使用する必要はありませんMVC http://knockoutmvc.com/CartEditor

をノックアウトしたい、何が本当に必要なの検証と物事のMVC側の安らかコントローラアクションにマップ作成/削除アクションではJavaScriptです。それを実現する方法はあなた次第です。ノックアウトはそれを簡単にします。

+0

しかし、これは実際にEditorFor()でそれを使用する方法を示していません。もはやそれを使用する必要はありませんか?この例では、BeginForm()およびpostメソッド内には表示されません。モデルのバインドは正しく行われますか? –

0

あなたは、次の操作を行う必要があります。

  1. あなたのコントローラにモデルを送信し、任期を1つの編集可能なフィールドをレンダリングします。
  2. あなたはこれを送信するか、追加をクリックしてより多くの用語を追加するように求めます。
  3. ユーザが「追加」をクリックすると、既存のフィールドのコピーを作成し、それらを空にするなど、新しいフィールドを作成することができます。
  4. ユーザーが提出すると、一連の用語を受け取り、データベースに追加するかどうかを判断するアクションに戻ります。または、上記の例のようなajaxを使用するか、this exampleから、サーバーに送信する内容がjson配列オブジェクトであり、名前付き要素ではないことがわかります。
  5. 作成時に処理することも、送信時に処理することもできます。

あなたのアプリケーションにもよりますので、ノックアウトは、古いコピーから新しいものを作成しているステップ3のクライアントで役に立ちます。同様にJQueryのテンプレートを訴えることができ、json2は古いブラウザをサポートしてシリアル化することができます。

あなたが理解しておく必要があるのは、一度クライアントにいったんモデルを送ってしまえば、サーバー側について心配しないでください。クライアント側でビルドしたものは、一度に1つのモデルを一度に送信して、タームIDやその他の情報でjsonを再実行するsaveTermアクション、またはjson配列としてsaveTermのコレクションを返すことができ、正常に動作します。

postbackで配列を送信することを考えていて、ajaxでない場合は、フォーム要素名を同じにしてターム入力フィールドを重複して送信するだけです。 MVCはそれらをjsonと同様に配列の配列にマップします。

1

このポストはNested Collection Models in MVC3です。Jarrett Meyer(ノックアウトを使用せずコード再利用を最大化するソリューションがあります)。

これは、追加と削除の両方の方法をカバーします。ここでaddメソッドの概要を説明します。

私はこれがどのように動作するかを見るモデル

public class Person { 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public IList<PhoneNumber> PhoneNumbers { get; set; } 
    public IList<EmailAddress> EmailAddresses { get; set; } 
    public IList<Address> Addresses { get; set; } 
} 

ビュー

//New.cshtml:  
@using (Html.BeginForm("New", "Person", FormMethod.Post)) 
{ 
    @Html.EditorForModel() 
    <p> 
    <button type="submit"> 
     Create Person 
    </button> 
    </p> 
} 

//Person.cshtml: 
@Html.AntiForgeryToken() 
@Html.HiddenFor(x => x.Id) 

<p> 
    <label>First Name</label> 
    @Html.TextBoxFor(x => x.FirstName) 
</p> 
<p> 
    <label>Last Name</label> 
    @Html.TextBoxFor(x => x.LastName) 
</p> 
<div id="phoneNumbers"> 
    @Html.EditorFor(x => x.PhoneNumbers) 
</div> 
<p> 
    @Html.LinkToAddNestedForm("Add Phone Number", "#phoneNumbers", ".phoneNumber", "PhoneNumbers", typeof(PhoneNumber)) 
</p> 

//PhoneNumber.cshtml: 
<div class="phoneNumber"> 
    <p> 
    <label>Telephone Number</label> 
    @Html.TextBoxFor(x => x.Number) 
    </p> 
    <br/> 
</div> 

ヘルパー

/// <param name="linkText">Text for Link</param> 
/// <param name="containerElement">where this block will be inserted in the HTML using a jQuery append method</param> 
/// <param name="counterElement">name of the class inserting, used for counting the number of items on the form</param> 
/// <param name="collectionProperty">the prefix that needs to be added to the generated HTML elements</param> 
/// <param name="nestedType">The type of the class you're inserting</param> 
public static IHtmlString LinkToAddNestedForm<TModel>(this HtmlHelper<TModel> htmlHelper, string linkText, 
    string containerElement, string counterElement, string collectionProperty, Type nestedType) 
{ 
    var ticks = DateTime.UtcNow.Ticks; 
    var nestedObject = Activator.CreateInstance(nestedType); 
    var partial = htmlHelper.EditorFor(x => nestedObject).ToHtmlString().JsEncode(); 

    partial = partial.Replace("id=\\\"nestedObject", "id=\\\"" + collectionProperty + "_" + ticks + "_"); 
    partial = partial.Replace("name=\\\"nestedObject", "name=\\\"" + collectionProperty + "[" + ticks + "]"); 

    var js = string.Format("javascript:addNestedForm('{0}','{1}','{2}','{3}');return false;", containerElement, 
     counterElement, ticks, partial); 

    TagBuilder tb = new TagBuilder("a"); 
    tb.Attributes.Add("href", "#"); 
    tb.Attributes.Add("onclick", js); 
    tb.InnerHtml = linkText; 

    var tag = tb.ToString(TagRenderMode.Normal); 
    return MvcHtmlString.Create(tag); 
} 

private static string JsEncode(this string s) 
{ 
    if (string.IsNullOrEmpty(s)) return ""; 
    int i; 
    int len = s.Length; 

    StringBuilder sb = new StringBuilder(len + 4); 
    string t; 

    for (i = 0; i < len; i += 1) 
    { 
     char c = s[i]; 
     switch (c) 
     { 
      case '>': 
      case '"': 
      case '\\': 
       sb.Append('\\'); 
       sb.Append(c); 
       break; 
      case '\b': 
       sb.Append("\\b"); 
       break; 
      case '\t': 
       sb.Append("\\t"); 
       break; 
      case '\n': 
       //sb.Append("\\n"); 
       break; 
      case '\f': 
       sb.Append("\\f"); 
       break; 
      case '\r': 
       //sb.Append("\\r"); 
       break; 
      default: 
       if (c < ' ') 
       { 
        //t = "000" + Integer.toHexString(c); 
        string tmp = new string(c, 1); 
        t = "000" + int.Parse(tmp, System.Globalization.NumberStyles.HexNumber); 
        sb.Append("\\u" + t.Substring(t.Length - 4)); 
       } 
       else 
       { 
        sb.Append(c); 
       } 
       break; 
     } 
    } 
    return sb.ToString(); 
} 

Javascriptを

//since the html helper can change the text of the item inserted but not the index, 
//this replaces the 'ticks' with the correct naming for the collection of properties 
function addNestedForm(container, counter, ticks, content) { 
    var nextIndex = $(counter).length; 
    var pattern = new RegExp(ticks, "gi"); 

    content = content.replace(pattern, nextIndex); 
    $(container).append(content); 
} 
+0

ネストされたフォームの追加は、遅いコンピュータでは起こり得ない 'ticks'プロパティの一意の値を持つことに大きく依存します。これを保証するには、GUIDを使用するか、次のようにします。System.Threading.Thread.Sleep(1);長い目盛り= DateTime.UtcNow.Ticks; –

関連する問題