2012-02-16 10 views
5

私は数週間、フォームに別の「成分」を追加する能力を与える動的フォームを作成する方法について、いくつかのチュートリアルに従っています。ここで私が追いつこうとした記事があります。 http://www.joe-stevens.com/2011/07/24/asp-net-mvc-2-client-side-validation-for-dynamic-fields-added-with-ajax/MVC 3 ViewModelを使用した動的フォーム

今すぐ追加リンクを使用して複数のrecipeIngredientsを追加しようとしていますが、リンクをクリックしたときに追加できる「ingredientName」と「recipeIngredient」Amountの両方が必要です。 私の問題は、私がアプリケーションを実行すると、recipeingredientのフォームには実際のテキストボックスの代わりに0があるということです。新しい成分の追加をクリックすると、追加するテキストボックスが表示されますが、量を入力して保存をクリックすると、モデルデータはコントローラに渡されません。

これを修正することから始めて、私はビューモデルを使用すべきかどうか、まったく間違っているかどうかはわかりません。ここに私のデータベース図http://i44.tinypic.com/xp1tog.jpgがあります。 recipeingredientため

@model ViewModels.RecipeViewModel 
@using Helpers; 



<h2>CreateFullRecipe</h2> 

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> 

    <script type="text/javascript"> 
     $().ready(function() { 
      $("#add-recipeingredient").click(function() { 
       $.ajax({ 
        url: '@Url.Action("GetNewRecipeIngredient")', 
        success: function (data) { 
         $(".new-recipeingredients").append(data); 
         Sys.Mvc.FormContext._Application_Load(); 
        } 
       }); 
      }); 
     }); 
    </script> 

    @using (Html.BeginForm()) 
    { 
      @Html.ValidationSummary(true) 
    <fieldset> 
     <legend>Recipe</legend> 

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


     <fieldset> 
      <legend>RecipeIngredients</legend> 
      <div class="new-recipeingredients"> 

       @Html.EditorFor(model => model.RecipeIngredients) 

      </div> 
      <div style="padding: 10px 0px 10px 0px"> 
       <a id="add-recipeingredient" href="javascript:void(0);">Add another</a> 
      </div> 
     </fieldset> 

     <div> 
      <input type="submit" value="CreateFullRecipe" /> 
     </div> 

    } 
<div> 
    @Html.ActionLink("Back to List", "Index") 
</div> 

マイeditortemplateview:

@model Models.RecipeIngredient 
@using Helpers; 

@using (Html.BeginAjaxContentValidation("form0")) 
    { 
     using (Html.BeginCollectionItem("RecipeIngedients")) 
     { 
    <div style="padding: 5px 0px 5px 0px"> 
     @Html.LabelFor(model => model.Amount) 
     @Html.EditorFor(model => model.Amount) 
     @Html.ValidationMessageFor(model => Model.Amount) 
    </div> 

     } 
    } 

MYコントローラーに関する方法:

[HttpGet] 
    public ActionResult CreateFullRecipe() 
    { 
     var recipeViewModel = new RecipeViewModel(); 
     return View(recipeViewModel); 
    } 

    // 
    // POST: /Recipe/Create 

    [HttpPost] 
    public ActionResult CreateFullRecipe(RecipeViewModel recipeViewModel) 
    { 
     if (ModelState.IsValid) 
     { 
      db.Recipes.Add(recipeViewModel.Recipe); 
      db.SaveChanges(); 
      int recipeID = recipeViewModel.Recipe.RecipeID; 
      for (int n = 0; n < recipeViewModel.RecipeIngredients.Count(); n++) 
      { 
       db.Ingredients.Add(recipeViewModel.Ingredients[n]); 
       int ingredientID = recipeViewModel.Ingredients[n].IngredientID; 

       recipeViewModel.RecipeIngredients[n].RecipeID = recipeID; 
       recipeViewModel.RecipeIngredients[n].IngredientID = ingredientID; 
       db.RecipeIngredients.Add(recipeViewModel.RecipeIngredients[n]); 

       db.SaveChanges(); 
      } 

      return RedirectToAction("Index"); 
     } 

     return View(recipeViewModel); 
    } 

    public ActionResult GetNewIngredient() 
    { 
     return PartialView("~/Views/Shared/IngredientEditorRow.cshtml", new Ingredient()); 
    } 

    public ActionResult GetNewRecipeIngredient() 
    { 
     return PartialView("~/Views/Shared/_RecipeIngredientEditRow.cshtml", new RecipeIngredient()); 
    } 
ここ

は私CREATEVIEWです

マイビューモデル:

public class RecipeViewModel 
    { 
     public RecipeViewModel() 
     { 
      RecipeIngredients = new List<RecipeIngredient>() { new RecipeIngredient() }; 
      Ingredients = new List<Ingredient>() { new Ingredient() }; 
      Recipe = new Recipe(); 
     } 

     public Recipe Recipe { get; set; } 
     public IList<Ingredient> Ingredients { get; set; } 
     public IList<RecipeIngredient> RecipeIngredients { get; set; } 
    } 
} 

私に知らせてください私の問題を助けるために必要なその他の情報がある場合。これは本当に私を夢中にしているので、私は何か助けを得ることを楽しみにしています ありがとう!

コントローラーポストメソッドcreatefullrecipeはあらかじめ定義されたリスト用で、ユーザーに別の要素を追加することを心配していないときに機能しました。ちょうど2つの成分私の見解には、これを作成するコードがコメントアウトされています。私が実際にやりたいことは、フォームモデルをコントローラに渡すビューモデルを取得し、createfullrecipeコントローラメソッドのようなデータを処理できることだけです。ここで

@* @for (int n = 0; n < Model.Ingredients.Count(); n++) 
    { 
     <div class="editor-label"> 
      @Html.LabelFor(model => model.Ingredients[n].IngredientName) 
     </div> 
       <div class="editor-field"> 
      @Html.EditorFor(model => model.Ingredients[n].IngredientName) 
      @Html.ValidationMessageFor(model => model.Ingredients[n].IngredientName) 
     </div> 

     <div class="editor-label"> 
      @Html.LabelFor(model => model.RecipeIngredients[n].Amount) 
     </div> 
       <div class="editor-field"> 
      @Html.EditorFor(model => model.RecipeIngredients[n].Amount) 
      @Html.ValidationMessageFor(model => model.RecipeIngredients[n].Amount) 
     </div> 
    }*@ 

私のモデルクラスです:

public class Recipe 
{ 
    public int RecipeID { get; set; } 
    public string RecipeName { get; set; } 
    public string Description { get; set; } 
    public int? PrepTime { get; set; } 
    public int? CookTime { get; set; } 
    public string ImageURL { get; set; } 

    public virtual IList<RecipeTag> RecipeTags { get; set; } 
    public virtual IList<Rating> Ratings { get; set; } 
    public virtual IList<RecipeStep> RecipeSteps { get; set; } 
    public virtual IList<RecipeIngredient> RecipeIngredients { get; set; } 

} 

public class RecipeIngredient 
{ 
    public int RecipeIngredientID { get; set; } 
    public string IngredientDesc { get; set; } 
    public string Amount { get; set; } 
    public int RecipeID { get; set; } 
    public int? IngredientID { get; set; } 

    public virtual Recipe Recipe { get; set; } 
    public virtual Ingredient Ingredient { get; set; } 
} 

public class Ingredient 
{ 

    public int IngredientID { get; set; } 
    public string IngredientName { get; set; } 

    public virtual ICollection<RecipeIngredient> RecipeIngredients { get; set; } 
} 
+0

私はこのブログ記事でこの問題について話しています。http://www.jasoncavett.com/2011/03/using-unobtrusive-jquery-validation.html – JasCav

+0

現在、検証が私の最大の問題であるかどうかはわかりません。私はコントローラにデータを送信する動的フォームを取得することはできません。例えば、レシピ名を入力すると、例えばajax以外のものは、コントローラに渡されたビューモデルに存在します。 – papayt

答えて

13

あなたのコードに問題がたくさんあります。私はあなたのニーズに合わせることができる簡単な例を説明するために、一歩一歩進みたいと思っています。

モデル:

public class RecipeViewModel 
{ 
    public Recipe Recipe { get; set; } 
    public IList<RecipeIngredient> RecipeIngredients { get; set; } 
} 

public class Recipe 
{ 
    public string RecipeName { get; set; } 
} 

public class RecipeIngredient 
{ 
    public int Amount { get; set; } 

    [Required] 
    public string IngredientDesc { get; set; } 
} 

コントローラー:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var recipeViewModel = new RecipeViewModel(); 
     return View(recipeViewModel); 
    } 

    [HttpPost] 
    public ActionResult Index(RecipeViewModel recipeViewModel) 
    { 
     if (!ModelState.IsValid) 
     { 
      // there wre validation errors => redisplay the view 
      return View(recipeViewModel); 
     } 

     // TODO: the model is valid => you could pass it to your 
     // service layer for processing 

     return RedirectToAction("Index"); 
    } 

    public ActionResult GetNewRecipeIngredient() 
    { 
     return PartialView("~/Views/Shared/EditorTemplates/RecipeIngredient.cshtml", new RecipeIngredient()); 
    } 
} 

ビュー(~/Views/Home/Index.cshtml):

@model RecipeViewModel 

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 
<script type="text/javascript"> 
    $(function() { 
     $('#add-recipeingredient').click(function() { 
      $.ajax({ 
       url: '@Url.Action("GetNewRecipeIngredient")', 
       type: 'POST', 
       success: function (data) { 
        $('.new-recipeingredients').append(data); 
       } 
      }); 
      return false; 
     }); 
    }); 
</script> 

@using (Html.BeginForm()) 
{ 
    @Html.ValidationSummary(true) 

    <div> 
     @Html.LabelFor(model => model.Recipe.RecipeName) 
     @Html.EditorFor(model => model.Recipe.RecipeName) 
     @Html.ValidationMessageFor(model => model.Recipe.RecipeName) 
    </div> 

    <fieldset> 
     <legend>RecipeIngredients</legend> 
     <div class="new-recipeingredients"> 
      @Html.EditorFor(model => model.RecipeIngredients) 
     </div> 
     <div style="padding: 10px 0px 10px 0px"> 
      <a id="add-recipeingredient" href="javascript:void(0);">Add another</a> 
     </div> 
    </fieldset> 

    <div> 
     <input type="submit" value="CreateFullRecipe" /> 
    </div> 
} 

エディタのテンプレート(~/Views/Shared/EditorTemplates/RecipeIngredient.cshtml):

@model RecipeIngredient 

@using (Html.BeginCollectionItem("RecipeIngredients")) 
{ 
    <div> 
     @Html.LabelFor(model => model.Amount) 
     @Html.EditorFor(model => model.Amount) 
     @Html.ValidationMessageFor(model => model.Amount) 
    </div> 

    <div> 
     @Html.LabelFor(model => model.IngredientDesc) 
     @Html.EditorFor(model => model.IngredientDesc) 
     @Html.ValidationMessageFor(model => model.IngredientDesc) 
    </div> 
} 
+0

本当に感謝してくれてありがとう。私は回答を助けるかもしれない私の既存のモデルを含めるために自分の投稿を更新しました。また、正規化されたテーブルIngredientとrecipeIngredientを1つのテーブル/モデルにまとめて、単純化する必要があるかどうかを判断するのに役立ちますか?私はまたあなたのよりクリーンなアプローチで私のjsとビューを更新しましたが、コントローラーのポストメソッドはまだフォームのデータを渡されたviewModelに持っていません。私はそれが私のモデルがどのようにセットアップされているかと関係があると思いますか? – papayt

+0

@papayt、私のコードを試しましたか?私が言ったように、あなたには多くの問題があります。たとえば、(Html.BeginCollectionItem( "RecipeIngedients")))を使用しているのに対し、正しいのは 'RecipeIngredients'ではなく' RecipeIngredients'と呼ばれているためです(Html.BeginCollectionItem( "RecipeIngredients"))。別の問題は、エディタテンプレートの名前と場所です。だから私は拡張機能のベースとして自分のコードを使用することをお勧めします。 –

+0

うわー、私は(Html.BeginCollectionItem( "RecipeIngedients"))、ありがとう!名前を変更したエディタテンプレートを、お勧めのフォルダに移動しました。そして...素晴らしいよ!私はちょうど別のrecipeIngredientを追加する機能を使って自分のコードの動的レシピの部分をテストしました。データは私のコントローラに渡されます。 :)今、私は自分のコードを整理し、原料モデルを動的フォームに統合してからコントローラでデータを処理する方法を考え続けます。大変ありがとうございました。 – papayt

関連する問題