why mvc validation does not work in my code? - asp.net-mvc

I have simple MVC code having a form with validation.but my validation for name property(required) does not work.I create BreakPoint in my controller after "InsertStudent" action result.
so I run that and fill the form without filling the name text box and I expect "IsValid" in my controller to be false.but it is true!!!
my view is:
#model HelloWorld.Models.student
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>AddStudent2</title>
</head>
<body>
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
#using (Html.BeginForm("InsertStudent","home",FormMethod.Post)) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>student</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Family)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Family)
#Html.ValidationMessageFor(model => model.Family)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</body>
</html>
and this is my controller:
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult index()
{
return View("home");
}
public ActionResult addstudent()
{
student stud = new student();
return View(stud);
}
public ActionResult InsertStudent(student stud)
{
if (ModelState.IsValid==true)
{
//sahih
}
else{
//ghalat
}
return View("addstudent");
}
public ActionResult AddStudent2()
{
student stud2 = new student();
return View(stud2);
}
}
}
and model is:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace HelloWorld.Models
{
public class student
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public string Family { get; set; }
[Required]
//[MaxLength(5)]
public int Age { get; set; }
public string Email { get; set; }
}
}
please help me

You do not have a Required attribute on your Name property. Add it and it the validation should fail
public class student
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Family { get; set; }
[Required]
public int Age { get; set; }
public string Email { get; set; }
}

I was able to solve the problem.
I had to put the [required] attribute below my name property instead of putting it above.
public class student
{
public int Id { get; set; }
[Required(AllowEmptyStrings = false)]
public string Name { get; set; }
[Required(AllowEmptyStrings=false)]
public string Family { get; set; }
[Required(AllowEmptyStrings = false)]
//[MaxLength(5)]
public int Age { get; set; }
public string Email { get; set; }
}

Related

why my checkboxes arent generated?

i have the following controller that calls view with template that generates a set of checkboxes
The controller / Action
public class CompoundsController : Controller
{
//
// GET: /Compounds/
testdbDBContext db = new testdbDBContext();
public ActionResult Index()
{
var comps = db.Compounds.Select(e => new CompoundModel { Id=e.Id, Code=e.Code, Name=e.Name, IsSelected = e.IsSelected }).ToList();
return View(new ChemicalsVM { cModel = comps});
}
}
The view
#model mvca1.Models.ChemicalsVM
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ChemicalsVM</legend>
<div class="editor-label">
#Html.LabelFor(model => model.SName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.SName)
#Html.ValidationMessageFor(model => model.SName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DName)
#Html.ValidationMessageFor(model => model.DName)
</div>
<div class="editor-label">
#Html.Label("Chemicals")
</div>
<div class="editor-field">
#Html.EditorFor(x=>x.cModel)
#Html.ValidationMessageFor(model => model.cModel)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
the template is:
#model mvca1.Models.CompoundModel
#{
ViewBag.Title = "rmplCompoundDB";
}
#Html.HiddenFor(x=>x.Id)
#Html.HiddenFor(x=>x.Code)
#Html.CheckBoxFor(x=>x.IsSelected, (Model.IsSelected)? new {#checked="checked"}:null)
#Html.LabelFor(x=>x.Name)
when i ran the code instead of generating checkboxes with labels it displays the id numbers (that should be hidden)
here is the video of what happens https://youtu.be/1Z2fwfBgyn8
why it does not display the checkboxes as expected?
UPDATE:
here is my ChemicalsVM
public class ChemicalsVM
{
public int Id { get; set; }
public string SName { get; set; }
public string DName { get; set; }
public List<CompoundModel> cModel { get; set; }
public ChemicalsVM()
{
cModel = new List<CompoundModel>();
}
}
here is the CompoundModel class
public class CompoundModel
{
public int Id { get; set; }
public string Code { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
The html being rendered means the ViewEngine is not finding the EditorTemplate. The template must be named the same as the class (i.e. CompoundModel.cshtml) and be located in either the /Views/Shared/EditorTemplates or /Views/Compounds/EditorTemplates folders.

Using one html.editorfor to fill in two model fields

Im trying to use only 1 html.editorfor to fill in two model field in each of my model.
I want the value of this editorfor to be also inserted to my Clientes0013.Client0013
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Client00130012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Client00130012)
</div>
and this one to be also inserted to Clientes0013.F1Pais00200013
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.F1Pais00200012)
#Html.ValidationMessageFor(model => model.CanaClie0012.F1Pais00200012)
</div>
Kindly show me what should be the right way of doing this.
My Table Model:
public partial class CanaClie0012
{
public string Client00130012 { get; set; }
public string F1Pais00200012 { get; set; }
public string F1Cana02530012 { get; set; }
public string Direcc0012 { get; set; }
public Nullable<System.DateTime> TmStmp0012 { get; set; }
}
public partial class Clientes0013
{
public string Client0013 { get; set; }
public string Nombre0013 { get; set; }
public string F1Pais00200013 { get; set; }
}
My Custom Model to combine the two table is:
public class ClientModel
{
public CanaClie0012 CanaClie0012 { get; set; }
public Clientes0013 Clientes0013 { get; set; }
}
My Controller:
[HttpPost]
public ActionResult ClientCreate(CanaClie0012 canaclie0012, Clientes0013 clientes0013)
{
ClientModel vm = new ClientModel();
if (ModelState.IsValid)
{
db.CanaClie0012.Add(canaclie0012);
db.Clientes0013.Add(clientes0013);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
My View:
#model MvcApplication1.Models.ClientModel
#{
ViewBag.Title = "ClientCreate";
}
<h2>ClientCreate</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>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ClientModel</legend>
<div class="editor-label">
Client Name
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Client00130012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Client00130012)
</div>
<div class="editor-label">
Pais
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.F1Pais00200012)
#Html.ValidationMessageFor(model => model.CanaClie0012.F1Pais00200012)
</div>
<div class="editor-label">
Address
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Direcc0012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Direcc0012)
</div>
<div class="editor-label">
Contact Number
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Clientes0013.Nombre0013)
#Html.ValidationMessageFor(model => model.Clientes0013.Nombre0013)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Got it.. modified my controller action to this one.
[HttpPost]
public ActionResult ClientCreate(CanaClie0012 canaclie0012, Clientes0013 clientes0013)
{
ClientModel vm = new ClientModel();
if (ModelState.IsValid)
{
clientes0013.Client0013 = canaclie0012.Client00130012;
clientes0013.F1Pais00200013 = canaclie0012.F1Pais00200012;
db.CanaClie0012.Add(canaclie0012);
db.Clientes0013.Add(clientes0013);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}

Multi Table in a view

I'm trying to make a strongly typed "Create View" so I could insert data into two tables simultaneously. However, when I create the view, the fields from my table are not included in my model. Can you tell what is the right way of doing this?
My Table Model:
public partial class CanaClie0012
{
public string Client00130012 { get; set; }
public string F1Pais00200012 { get; set; }
public string F1Cana02530012 { get; set; }
public string Direcc0012 { get; set; }
public Nullable<System.DateTime> TmStmp0012 { get; set; }
}
public partial class Clientes0013
{
public string Client0013 { get; set; }
public string Nombre0013 { get; set; }
public string F1Pais00200013 { get; set; }
}
My Custom Model to combine the two table is:
public class ClientModel
{
public IQueryable<CanaClie0012> CanaClie0012 { get; set; }
public IQueryable<Clientes0013> Clientes0013 { get; set; }
}
My Controller: (Not really sure if im this correctly)
[HttpPost]
public ActionResult ClientCreate(CanaClie0012 canaclie0012, Clientes0013 clientes0013)
{
ClientModel vm = new ClientModel();
if (ModelState.IsValid)
{
db.CanaClie0012.Add(canaclie0012);
db.SaveChanges();
db.Clientes0013.Add(clientes0013);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(vm);
}
My view:
#model MvcApplication1.Models.ClientModel
#{
ViewBag.Title = "ClientCreate";
}
<h2>ClientCreate</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>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ClientModel</legend>
<div class="editor-label">
Client Name
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Client00130012)
#Html.ValidationMessageFor(model => model.Client00130012)
</div>
<div class="editor-label">
Pais
</div>
<div class="editor-field">
#Html.EditorFor(model => model.F1Pais00200012)
#Html.ValidationMessageFor(model => model.F1Pais00200012)
</div>
<div class="editor-label">
Address
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Direcc0012)
#Html.ValidationMessageFor(model => model.Direcc0012)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Nombre0013)
#Html.ValidationMessageFor(model => model.Nombre0013)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
One big problem is that your view is strongly-typed to your ClientModel class. This class does not include the members that you are referencing in your view. Instead, that class includes lists of objects that include those members. At this point, your view probably doesn't even compile.
Try changing your ClientModel class as follows:
public class ClientModel
{
public CanaClie0012 CanaClie0012 { get; set; }
public Clientes0013 Clientes0013 { get; set; }
}
then your view would reference the members such as:
<div class="editor-label">
Client Name
</div>
<div class="editor-field">
#Html.EditorFor(model => model.CanaClie0012.Client00130012)
#Html.ValidationMessageFor(model => model.CanaClie0012.Client00130012)
</div>
similarly for members of your Clientes0013 members.
One additional thing: you don't need to call db.SaveChanges(); twice in your controller. Instead, insert into both tables and do a single save:
db.CanaClie0012.Add(canaclie0012);
db.Clientes0013.Add(clientes0013);
db.SaveChanges();

Adding Foreign key value from dropdown box / data not showing in dropdown

I am working with a create method for my renter controller. Each new renter has a corresponding building that its attached to. I want it so that in my create view it shows the buildings name and then populates the table with its corresponding id. I cannot figure out how to get this to work.
public class Renter
{
[Key]
public int RenterId { get; set; }
public int BuildingID { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
[DataType(DataType.PhoneNumber)]
public String Phone { get; set; }
[DataType(DataType.EmailAddress)]
public String Email { get; set; }
public Boolean IsApproved { get; set; }
//Foreign Key
// [Required]
public virtual Building Building { get; set; }
}
public class Building
{
[Key]
public int BuildingId { get; set; }
public string BuildingName { get; set; }
public virtual ICollection<Renter> Residents { get; set; }
public int ManagerId { get; set; }
public virtual Manager Manager { get; set; }
}
public class Manager
{
[Key]
public int ManagerId { get; set; }
public virtual ICollection<Renter> Tenants { get; set; }
public virtual ICollection<Building> Buildings { get; set; }
}
Create view
#model RPMS.Models.Renter
#{
ViewBag.Title = "Create";
}
<h2>Create</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>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Renter</legend>
<div class="editor-label">
#Html.LabelFor(model => model.BuildingID, "Building")
</div>
<div class="editor-field">
#Html.DropDownList("BuildingID", String.Empty)
#Html.ValidationMessageFor(model => model.BuildingID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Phone)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Phone)
#Html.ValidationMessageFor(model => model.Phone)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IsApproved)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.IsApproved)
#Html.ValidationMessageFor(model => model.IsApproved)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Currently when I run this and go to select the building, nothing shows up in the dropdown box even though I have initialized the data
protected override void Seed(RPMSContext context)
{
var renters = new List<Renter>
{
new Renter {RenterId = 1, BuildingID = 1, FirstName="Bradley", LastName="Woods",Phone="614-218-0294", Email="bradleydeanwoods#gmail.com",IsApproved = true},
};
renters.ForEach(s => context.Renters.Add(s));
context.SaveChanges();
var buildings = new List<Building>
{
new Building {BuildingId = 1, BuildingName="Annex at River South",ManagerId = 1},
};
buildings.ForEach(s => context.Buildings.Add(s));
context.SaveChanges();
var managers = new List<Manager>
{
new Manager {ManagerId = 1,},
};
managers.ForEach(s => context.Managers.Add(s));
context.SaveChanges();
}
And finally here is the DbContext
public class RPMSContext : DbContext
{
public DbSet<Renter> Renters { get; set; }
public DbSet<Building> Buildings { get; set; }
public DbSet<Manager> Managers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Thanks for your help in advance for helping me to get past this sticking point.
Update The seed data shows when I take out the foreign key relationships so that is what I have done for now and just decided to move on.

MVC 3 Dynamic Form Using a ViewModel

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

Resources