Reputation: 1815
I am creating a new recipe entry form and I am finding two interesting problems:
Ideally, I'd like the ingredient collection to be under the recipe item, but I'll settle for just getting the ingredient collection to write to the parameter.
Here are the two models (Generated by entity framework):
Recipe:
public int recipeId { get; set; }
[Required]
[StringLength(255)]
[DisplayName("Name")]
public string name { get; set; }
[DisplayName("Category")]
public int? mealCategoryId { get; set; }
[DisplayName("Preperation Time")]
public int? prepTime { get; set; }
[DisplayName("Cook Time")]
public int? cookTime { get; set; }
[DisplayName("Stand Time")]
public int? standTime { get; set; }
[DisplayName("Serving Size")]
public int? servingSize { get; set; }
[DisplayName("Status")]
public int recipeStatusId { get; set; }
[DisplayName("Description")]
[UIHint("Multiline")]
public string description { get; set; }
public virtual ICollection<Direction> Directions { get; set; }
public virtual ICollection<Image> Images { get; set; }
public virtual ICollection<Ingredient> Ingredients { get; set; }
public virtual MealCategory MealCategory { get; set; }
public virtual ICollection<Nutrition> Nutritions { get; set; }
public virtual ICollection<Rating> Ratings { get; set; }
public virtual RecipeStatus RecipeStatus { get; set; }
}
Ingredient:
public partial class Ingredient
{
public int ingredientId { get; set; }
public int? recipeId { get; set; }
public int? subCategoryId { get; set; }
public int measurementId { get; set; }
public int amount { get; set; }
public virtual Recipe Recipe { get; set; }
public virtual SubCategory SubCategory { get; set; }
public virtual Measurement Measurement { get; set; }
}
View Code:
<div class="form-horizontal">
<h4>Ingredients</h4>
<hr />
<table class="table IngredientList">
<tr>
<th>
@Html.LabelFor(model => model.Recipe.Ingredients)
</th>
<th>
@Html.LabelFor(model => model.SelectedMeasurementId)
</th>
<th>
@Html.Label("Amount")
</th>
</tr>
@for (int i = 0; i < Model.Recipe.Ingredients.Count; i++)
{
<tr>
<td>
@Html.DropDownListFor(m => Model.Recipe.Ingredients.ElementAt(i).ingredientId, Model.SubIngredients, new { @class = "form-control input-block-level" })
</td>
<td>
@Html.DropDownListFor(m => Model.Recipe.Ingredients.ElementAt(i).measurementId, Model.Measurements, new { @class = "form-control input-block-level" })
</td>
<td>
@Html.TextBoxFor(m => Model.Recipe.Ingredients.ElementAt(i).amount, new { @class = "form-control input-block-level" })
</td>
</tr>
}
</table>
</div>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Recipe recipe, int SelectedCategoryId, List<Ingredient> Ingredients)
{
recipe.mealCategoryId = SelectedCategoryId;
recipe.recipeStatusId = 1;
if (ModelState.IsValid)
{
dbContext.Entry(recipe).State = EntityState.Added;
dbContext.SaveChanges();
return RedirectToAction("Details", new {id = recipe.recipeId});
}
return View(recipe);
}
So, if I have the parameter set to List Ingredients then null is returned. If I have it set to Ingredient Ingredients then I get only the first of four ingredients. (I have the model set to create 4 ingredient records upon loading.)
My question is: How do I get it to pass the collection of ingredients?
EDIT:
I have confirmed that the request is sending all 4 of the ingredients over. It seems to be a problem with the binding.
Upvotes: 0
Views: 1660
Reputation: 5590
Create your own ViewModels to hold Data, do not use Entity Frameworks pre generated classes for Model Binding. Here's a very basic example for Proof of Concept
public class Recipe
{
public int RecipeId {get; set;}
public List<Ingredients> Ingredient {get; set;}
}
public class Ingredients
{
public string Name {get; set;}
public string Amount {get; set;}
}
public ActionResult Index()
{
Recipe model = new Recipe();
model.RecipeId = 1;
model.Ingredient = new List<Ingredients>();//Better if done inside Constructor
model.Ingredient.Add(new Ingredients{Name = "Salt",
Amount = "A Pinch"});
model.Ingredient.Add(new Ingredients{Name = "Hot Sauce",
Amount = "HOT HOT HOT!"});
return View(model);
}
View
@Html.TextBoxFor(x => x.RecipeId)
for (int i = 0; i < Model.Ingredient.Count; i++)
{
@Html.TextBoxFor(modelItem => Model.Ingredient[i].Name)
@Html.TextBoxFor(modelItem => Model.Ingredient[i].Amount)
}
And post it and it will bind
Upvotes: 3