MVC 3动态表单使用视图模型 [英] MVC 3 Dynamic Form Using a ViewModel

查看:146
本文介绍了MVC 3动态表单使用视图模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试了几个星期跟随关于如何创建一个动态的形式给予再添成分的形式能力夫妻教程。下面是我试图按照文章。 <一href=\"http://www.joe-stevens.com/2011/07/24/asp-net-mvc-2-client-side-validation-for-dynamic-fields-added-with-ajax/\" rel=\"nofollow\">http://www.joe-stevens.com/2011/07/24/asp-net-mvc-2-client-side-validation-for-dynamic-fields-added-with-ajax/

现在我只是努力增加使用添加链接多个recipeIngredients,但我需要有两个ingredientName和recipeIngredient金额能够链接被点击时要添加。
我的问题是,当我运行的应用程序,为recipeingredient形式有一个0,​​而不是实际的文本框。当我点击添加新的成分,我能得到一个文本框添加,但是当我在金额类型,然后点击保存,模型数据的心不是被传递给控制器​​。

我只是不知道用在哪里解决这个就要开始了,我还是我不知道我是否应该使用视图模型,如果我要去这个完全错误的。这里是我的数据库图表 http://i44.tinypic.com/xp1tog.jpg

这是我CreateView的:

  @model ViewModels.RecipeViewModel
@using助手;&LT; H2&GT; CreateFullRecipe&LT; / H&GT;&LT;脚本的src =@ Url.Content(〜/脚本/ jquery.validate.min.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;
&LT;脚本的src =@ Url.Content(〜/脚本/ jquery.validate.unobtrusive.min.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;    &LT;脚本类型=文/ JavaScript的&GT;
        $()。就绪(函数(){
            $(#附加recipeingredient)。点击(函数(){
                $阿贾克斯({
                    网址:'@ Url.Action(GetNewRecipeIngredient)',
                    成功:功能(数据){
                        $(新recipeingredients。)追加(数据)。
                        Sys.Mvc.FormContext._Application_Load();
                    }
                });
            });
        });
    &LT; / SCRIPT&GT;  @using(Html.BeginForm())
  {
          @ Html.ValidationSummary(真)
    &LT;&字段集GT;
        &LT;传奇&GT;&配方LT; /传说&GT;        &LT; D​​IV CLASS =编辑标记&GT;
            @ Html.LabelFor(型号=&GT; model.Recipe.RecipeName)
        &LT; / DIV&GT;
        &LT; D​​IV CLASS =主编场&GT;
            @ Html.EditorFor(型号=&GT; model.Recipe.RecipeName)
            @ Html.ValidationMessageFor(型号=&GT; model.Recipe.RecipeName)
        &LT; / DIV&GT;
    &LT; /字段集&GT;
        &LT;&字段集GT;
            &LT;传奇&GT; RecipeIngredients&LT; /传说&GT;
            &LT; D​​IV CLASS =新recipeingredients&GT;                @ Html.EditorFor(型号=&GT; model.RecipeIngredients)            &LT; / DIV&GT;
            &LT; D​​IV的风格=填充:10px的0像素10px的0像素&GT;
                &LT;一个ID =附加recipeingredient的href =JavaScript的:无效(0);&gt;添加另一个&LT; / A&GT;
            &LT; / DIV&GT;
        &LT; /字段集&GT;        &LT; D​​IV&GT;
            &LT;输入类型=提交值=CreateFullRecipe/&GT;
        &LT; / DIV&GT;  }
&LT; D​​IV&GT;
    @ Html.ActionLink(返回目录,索引)
&LT; / DIV&GT;

我的editortemplateview为recipeingredient:

  @model Models.RecipeIngredient
@using助手;@using(Html.BeginAjaxContentValidation(form0))
    {
        使用(Html.BeginCollectionItem(RecipeIngedients))
        {
    &LT; D​​IV的风格=填充:为5px 0像素为5px 0像素&GT;
        @ Html.LabelFor(型号=&GT; model.Amount)
        @ Html.EditorFor(型号=&GT; model.Amount)
        @ Html.ValidationMessageFor(型号=&GT; Model.Amount)
    &LT; / DIV&GT;        }
    }

我的有关方法控制器:

  [HTTPGET]
    公众的ActionResult CreateFullRecipe()
    {
        VAR recipeViewModel =新RecipeViewModel();
        返回查看(recipeViewModel);
    }    //
    // POST:/方/创建    [HttpPost]
    公众的ActionResult CreateFullRecipe(RecipeViewModel recipeViewModel)
    {
        如果(ModelState.IsValid)
        {
            db.Recipes.Add(recipeViewModel.Recipe);
            db.SaveChanges();
            INT recipeID = recipeViewModel.Recipe.RecipeID;
            对于(INT N = 0; N&LT; 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();
            }            返回RedirectToAction(「指数」);
        }        返回查看(recipeViewModel);
    }    公众的ActionResult GetNewIngredient()
    {
        返回PartialView(〜/查看/共享/ IngredientEditorRow.cshtml,新的成分());
    }    公众的ActionResult GetNewRecipeIngredient()
    {
        返回PartialView(〜/查看/共享/ _RecipeIngredientEditRow.cshtml,新RecipeIngredient());
    }

我的视图模型:

 公共类RecipeViewModel
    {
        公共RecipeViewModel()
        {
            RecipeIngredients =新的List&LT; RecipeIngredient&GT;(){新RecipeIngredient()};
            配料=新的List&LT;性成分GT;(){新成分()};
            配方=新配方();
        }        公共配方配方{搞定;组; }
        公众的IList&LT;性成分GT;配料{搞定;组; }
        公众的IList&LT; RecipeIngredient&GT; RecipeIngredients {搞定;组; }
    }
}

如果有帮助我的问题出来了,请让我知道所需的任何其他信息。这是真的快把我逼疯了,所以我期待着任何帮助,我可以得到
谢谢!

我也想提一提,该控制器POST方法createfullrecipe为pre定义的列表和它的工作时,我不是担心使用户能够添加其他成分的能力,而我只是默认的形式有2成分和我的看法是这样注释掉code来创建它们。我真正想要做的就是让视图模型将表单数据传递给控制器​​和像我createfullrecipe控制器的方法现在这样我能处理的数据。

  @ * @for(INT N = 0; N&LT; Model.Ingredients.Count(); N ++)
    {
        &LT; D​​IV CLASS =编辑标记&GT;
            @ Html.LabelFor(型号=&GT; model.Ingredients [N] .IngredientName)
        &LT; / DIV&GT;
                &LT; D​​IV CLASS =主编场&GT;
            @ Html.EditorFor(型号=&GT; model.Ingredients [N] .IngredientName)
            @ Html.ValidationMessageFor(型号=&GT; model.Ingredients [N] .IngredientName)
        &LT; / DIV&GT;        &LT; D​​IV CLASS =编辑标记&GT;
            @ Html.LabelFor(型号=&GT; model.RecipeIngredients [N] .Amount)
        &LT; / DIV&GT;
                &LT; D​​IV CLASS =主编场&GT;
            @ Html.EditorFor(型号=&GT; model.RecipeIngredients [N] .Amount)
            @ Html.ValidationMessageFor(型号=&GT; model.RecipeIngredients [N] .Amount)
        &LT; / DIV&GT;
    } * @

下面是我的模型类:

 公共类食谱
{
    公众诠释RecipeID {搞定;组; }
    公共字符串RecipeName中获得{;组; }
    公共字符串描述{搞定;组; }
    公众诠释? $ P $ {ppTime获得;组; }
    公众诠释? CookTime {搞定;组; }
    公共字符串IMAGEURL {搞定;组; }    公共虚拟的IList&LT; RecipeTag&GT; RecipeTags {搞定;组; }
    公共虚拟的IList&LT;评价&GT;评级{搞定;组; }
    公共虚拟的IList&LT; RecipeStep&GT; RecipeSteps {搞定;组; }
    公共虚拟的IList&LT; RecipeIngredient&GT; RecipeIngredients {搞定;组; }}公共类RecipeIngredient
{
    公众诠释RecipeIngredientID {搞定;组; }
    公共字符串IngredientDesc {搞定;组; }
    公共字符串金额{搞定;组; }
    公众诠释RecipeID {搞定;组; }
    公众诠释? IngredientID {搞定;组; }    公共虚拟配方配方{搞定;组; }
    公共虚拟组分组分{搞定;组; }
}公共类成分
{    公众诠释IngredientID {搞定;组; }
    公共字符串IngredientName {搞定;组; }    公共虚拟的ICollection&LT; RecipeIngredient&GT; RecipeIngredients {搞定;组; }
}


解决方案

有很多的问题与你的code。我preFER一步,以说明一个简单的例子,你可以适应您的需求走一步。

模型:

 公共类RecipeViewModel
{
    公共配方配方{搞定;组; }
    公众的IList&LT; RecipeIngredient&GT; RecipeIngredients {搞定;组; }
}公共类食谱
{
    公共字符串RecipeName中获得{;组; }
}公共类RecipeIngredient
{
    公众诠释金额{搞定;组; }    [需要]
    公共字符串IngredientDesc {搞定;组; }
}

控制器:

 公共类HomeController的:控制器
{
    公众的ActionResult指数()
    {
        VAR recipeViewModel =新RecipeViewModel();
        返回查看(recipeViewModel);
    }    [HttpPost]
    公众的ActionResult指数(RecipeViewModel recipeViewModel)
    {
        如果(!ModelState.IsValid)
        {
            //有目不转睛地验证错误=&GT;重新显示视图
            返回查看(recipeViewModel);
        }        // TODO:该模型是有效的= GT;你可以把它传递给你的
        处理//服务层        返回RedirectToAction(「指数」);
    }    公众的ActionResult GetNewRecipeIngredient()
    {
        返回PartialView(〜/查看/共享/ EditorTemplates / RecipeIngredient.cshtml,新RecipeIngredient());
    }
}

查看(〜/查看/主页/ Index.cshtml

  @model RecipeViewModel&LT;脚本的src =@ Url.Content(〜/脚本/ jquery.validate.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;
&LT;脚本的src =@ Url.Content(〜/脚本/ jquery.validate.unobtrusive.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;
&LT;脚本类型=文/ JavaScript的&GT;
    $(函数(){
        $('#附加recipeingredient')。点击(函数(){
            $阿贾克斯({
                网址:'@ Url.Action(GetNewRecipeIngredient)',
                输入:POST,
                成功:功能(数据){
                    $('。新recipeingredients')追加(数据);
                }
            });
            返回false;
        });
    });
&LT; / SCRIPT&GT;@using(Html.BeginForm())
{
    @ Html.ValidationSummary(真)    &LT; D​​IV&GT;
        @ Html.LabelFor(型号=&GT; model.Recipe.RecipeName)
        @ Html.EditorFor(型号=&GT; model.Recipe.RecipeName)
        @ Html.ValidationMessageFor(型号=&GT; model.Recipe.RecipeName)
    &LT; / DIV&GT;    &LT;&字段集GT;
        &LT;传奇&GT; RecipeIngredients&LT; /传说&GT;
        &LT; D​​IV CLASS =新recipeingredients&GT;
            @ Html.EditorFor(型号=&GT; model.RecipeIngredients)
        &LT; / DIV&GT;
        &LT; D​​IV的风格=填充:10px的0像素10px的0像素&GT;
            &LT;一个ID =附加recipeingredient的href =JavaScript的:无效(0);&gt;添加另一个&LT; / A&GT;
        &LT; / DIV&GT;
    &LT; /字段集&GT;    &LT; D​​IV&GT;
        &LT;输入类型=提交值=CreateFullRecipe/&GT;
    &LT; / DIV&GT;
}

编辑模板(〜/查看/共享/ EditorTemplates / RecipeIngredient.cshtml

  @model RecipeIngredient@using(Html.BeginCollectionItem(RecipeIngredients))
{
    &LT; D​​IV&GT;
        @ Html.LabelFor(型号=&GT; model.Amount)
        @ Html.EditorFor(型号=&GT; model.Amount)
        @ Html.ValidationMessageFor(型号=&GT; model.Amount)
    &LT; / DIV&GT;    &LT; D​​IV&GT;
        @ Html.LabelFor(型号=&GT; model.IngredientDesc)
        @ Html.EditorFor(型号=&GT; model.IngredientDesc)
        @ Html.ValidationMessageFor(型号=&GT; model.IngredientDesc)
    &LT; / DIV&GT;
}

I have been trying for weeks to follow a couple tutorials on how to create a dynamic form giving the ability to add another "ingredient" to the form. Here is the article I tried to follow. http://www.joe-stevens.com/2011/07/24/asp-net-mvc-2-client-side-validation-for-dynamic-fields-added-with-ajax/

Right now Im just working on adding multiple recipeIngredients using the add link, but I will need to have both the "ingredientName", and "recipeIngredient" Amount able to be added when the link is clicked. My problem is that when I run the app, the form for the recipeingredient has a 0 instead of an actual textbox. When I click add new ingredient, I am able to get a textbox to add, but when I type in an amount and click save, the model data isnt being passed to the controller..

I just dont even know where to begin with fixing this, I am not sure if I should be using a viewmodel or if Im going about this entirely wrong. Here is my database diagram http://i44.tinypic.com/xp1tog.jpg.

Here is my CreateView:

    @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>

My editortemplateview for recipeingredient:

@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 Controller relating methods:

[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());
    }

My View Model:

    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; }
    }
}

If there is any other information needed to help my problem out please let me know. This is really driving me crazy so I look forward to any help I can get Thank you!

I would also like to mention that the controller post method createfullrecipe is for a pre defined list and it worked when I wasnt worried about giving the user the ability to add another ingredient, rather I just defaulted the form to have 2 ingredients and my view had this commented out code to create them. All I really want to do is get the viewmodel to pass the form data to the controller and I can handle the data like my createfullrecipe controller method does now.

@*    @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>
    }*@

Here are my model classes:

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; }
}

解决方案

There are lots of issues with your code. I prefer to go step by step in order to illustrate a simplified example that you could adapt to your needs.

Models:

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; }
}

Controller:

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());
    }
}

View (~/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>
}

Editor template (~/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>
}

这篇关于MVC 3动态表单使用视图模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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