Pass 'list' model into and out of a view - c#

Wonder if someone could point me in the right direction please?
Basically I'm trying to create a page to allow someone to enter data (golf) on a number (18) of holes and basically I'm unsure of how it's done.
In the model I've created the following:
namespace BGSociety.Models
{
public class CreateCourseHolesViewModel
{
public int holeNumber { get; set; }
public int par { get; set; }
public int si { get; set; }
public int distance { get; set; }
}
}
In the Index event of the controller I've got:
TempData["holes"] = getHoles();
protected List<CreateCourseHolesViewModel> getHoles()
{
var holes = new List<CreateCourseHolesViewModel>();
for (int i =1; i < 19; i++)
{
holes.Add(new CreateCourseHolesViewModel { holeNumber = i });
}
return holes;
}
And I'm passing this into the view:
return PartialView("CreateCourseHoles", TempData["holes"]);
In the view I can loop through the list and display the whole number with a textbox next to each one to allow for the entry of par, si and distance.
var zHoles = TempData["holes"] as IEnumerable<BGSociety.Models.CreateCourseHolesViewModel>;
foreach (var hole in zHoles)
{
<div class="row">
<div class="col-sm-1">
<p>#hole.holeNumber</p>
</div>
<div class="col-sm-6">
<div class="form-group">
<div class="col-xs-12">
#Html.ValidationMessageFor(m => hole.par)
#Html.TextBox("par", TempData["par"], new { #class = "form-control", placeholder = "Par", name = "Par" })
</div>
</div>
</div>
</div>
}
But I just can't work out how to pass this populated list back to the controller for me to enter the data into the DB.
There's a great chance that I've gone about this the wrong way (!) but if someone could spare a few minutes to assist that would be marvelous!
Thanks,
Sx

TempData is not meant to be passed as parameters to your PartialView. Even if you dont pass it as parameter; you can still access it. I suggest that you do this instead:
return PartialView("CreateCourseHoles", getHoles());
then your partial view you can you have
#model IEnumerable<BGSociety.Models.CreateCourseHolesViewModel>
and wrap all that for loop in a form:
<form method="post" action="wherever you want to post it to">
foreach (var hole in Model)
{
<div class="row">
<div class="col-sm-1">
<p>#hole.holeNumber</p>
</div>
<div class="col-sm-6">
<div class="form-group">
<div class="col-xs-12">
#Html.ValidationMessageFor(m => hole.par)
#Html.TextBox("par", TempData["par"], new { #class = "form-control", placeholder = "Par", name = "Par" })
</div>
</div>
</div>
</div>
}
</form>

Related

Can not access the composite key table through a view, in order to enter data or assign the correct primary key in that table?

I'm trying to develop an ASP.NET MVC application using C# and EF with a code-first approach.
I have two classes Actors and Movies which have many-to-many relationships (an Actor can be in many Movies, a Movie can have many Actors).
Everything is working properly, but I can not access the intermediate (MoviesActors) table through a view (this table is generated automatically as a result of the many-to-many relationship between Actors and Movies). I want to access this table so that I could assign the correct primary keys to determine things like "How many movies does a particular actor have?" and "How many actors have played a role in a particular movie?".
These are my models:
public class Actors
{
public Actors()
{
this.mvz = new HashSet<Movies>();
}
public int Id { get; set; }
public string actor_name { get; set; }
public string country { get; set; }
public virtual ICollection<Movies> mvz { get; set; }
}
public class Movies
{
public Movies()
{
this.actz = new HashSet<Actors>();
}
public int Id { get; set; }
public string Movie_title { get; set; }
public string genre { get; set; }
public virtual ICollection<Actors> actz { get; set; }
}
I have two models as above and three tables in database.
Now from a view, I can access the actors model and the movies model but when it comes to the intermediate table (MoviesActors), I can not access its model because it does not exist, which means I can not reference MoviesActors in a view and can't enter data through a form.
I would like to ask if my approach is correct or not, I mean in a real world application do we have to access the composite key table and do the data entry, or is there any better approach to solve this issue?
By the way this is the controller:
public ActionResult DataEntry()
{
return View();
}
[HttpPost]
public ActionResult Add(??? mva)
{
_context.act.Add(mva.act);
_context.mvz.Add(mva.mvz);
_context.SaveChanges();
return RedirectToAction("Index","Actors");
}
And this is the view:
#model Many_To_Many_Relationship_Latest.?.?
#{
ViewBag.Title = "DataEntry";
Layout = "~/Views/Shared/_Layout.cshtml";
}
At the top, I should be able to access the MoviesActors table via Model or ViewModel (Check the two places with question marks) but I'm not able to do so.
If anyone having expertise in this regard is reading this post, kindly guide me with the correct logic or any other approach that helps me get the result.
Many thanks in advance.
This is my new razor view
#model Many_To_Many_Relationship_Latest.ViewModel.MoviesActorsViewModel
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
#{
ViewBag.Title = "DataEntry";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h5>Enter Data in Movies_Actors Table</h5>
#using (Html.BeginForm("Add","MoviesActors"))
{
<div class="form-group">
#Html.LabelFor(a=> a.mvz.Movie_title)
#Html.TextBoxFor(a=> a.mvz.Movie_title, new { #class="form-control"})
</div>
<div class="form-group">
#Html.LabelFor(a => a.mvz.genre)
#Html.TextBoxFor(a => a.mvz.genre, new { #class = "form-control" })
</div>
foreach (var item in Model.act)
{
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox control-group">
<label>
<!-- SEE id property here, I've made it dynamic -->
<input type="checkbox" id="cb_#item.Id" value="#item.Id" class="checkBoxClass" />
<label>#item.actor_name</label>
</label>
</div>
</div>
</div>
}
<div>
<input type="hidden" name="Ids" id="Ids" />
</div>
<button type="submit" class="btn btn-primary">Save</button>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script>
$(function () {
var ids = [];
$(".checkBoxClass").change(function () {
if (this.checked) {
ids.push(this.value);
}
else {
var index = ids.indexOf(this.value);
ids.splice(index, 1);
}
$('#ids').val(ids);
});
});
</script>
The intermediate table is hidden by Entity framework but don't worry mvc have fabulous feature that is ViewModel to do your job that means you can to create view for intermediate table like MoviesActors
So for,
1) You have to create one view model for your intermediate table like
public class MoviesActorsViewModel
{
public MoviesActorsViewModel()
{
mvz = new Movies();
act = new Actors();
}
public Movies mvz { get; set; }
public Actors act { get; set; }
}
2) Add view for above view model like
public ActionResult GetView()
{
MoviesActorsViewModel mcvm = new MoviesActorsViewModel();
return View(mcvm);
}
3) Then your view for above action method like.
The below razor is for your understanding purpose only. your actual razor may differ from this.
#model WebApplication2.Controllers.MoviesActorsViewModel
#{
ViewBag.Title = "GetView";
}
<h2>GetView</h2>
#using (Html.BeginForm("Create", "Default", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MoviesActorsViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
//mvz fields below
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.movie_title, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.genre, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
//act fields below
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.act.actor_name, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.act.country_of_birth, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
4) After you submit your form then your post method will add your mvz and act like
[HttpPost]
public ActionResult Create(MoviesActorsViewModel mcvm)
{
_context.mvz.Add(mcvm.mvz);
_context.actrs.Add(mcvm.act);
return RedirectToAction("GetView", "Default");
}
Note: The above code snippet is for one movie and one actor.
So if you want to add multiple actors to single movie then change your act property in MoviesActorsViewModel to List
Like public List<Actors> act { get; set; } and add multiple textbox in view and after posting your form to action method Create add those multiple actors like _context.actrs.AddRange(mcvm.act);
Edit:
I have to register a new actor too. But I want to select actors from the actors table and assign them to the new movies that gets registered.
If you have to assign multiple actors to movie while adding new movie then
1) You view model is
public class MoviesActorsViewModel
{
public MoviesActorsViewModel()
{
mvz = new Movies();
act = new List<Actors>();
}
public Movies mvz { get; set; }
public List<Actors> act { get; set; }
public string[] ids { get; set; }
}
2) Populate your actors from db to view model's act list from your get view action method
public ActionResult GetView()
{
MoviesActorsViewModel mcvm = new MoviesActorsViewModel();
mcvm.act = _context.actrs.ToList();
return View(mcvm);
}
3) In razor view you have to enter one movie and choose multiple actors for it then simply take checkbox for each of actors and add its respective id values to array and then pass this array with form submit.
#model WebApplicationMVC1.Controllers.MoviesActorsViewModel
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
#{
ViewBag.Title = "GetView";
}
<h2>GetView</h2>
#using (Html.BeginForm("Create", "Default1", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MoviesActorsViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
//mvz fields below
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.movie_title, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
#Html.TextBoxFor(model => model.mvz.genre, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
//act fields below from list of actors
#foreach (var item in Model.act)
{
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox control-group">
<label>
<!-- SEE id property here, I've made it dynamic -->
<input type="checkbox" id="cb_#item.Id" value="#item.Id" class="checkBoxClass" />
<label>#item.actor_name</label>
</label>
</div>
</div>
</div>
}
<div>
<input type="hidden" name="ids" id="ids" />
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script>
$(function () {
var ids = [];
$(".checkBoxClass").change(function () {
if (this.checked) {
ids.push(this.value);
}
else {
var index = ids.indexOf(this.value);
ids.splice(index, 1);
}
$('#ids').val(ids);
});
});
</script>
4) After submit your form to below action you can loop through each of id of actor and save it to database with movie
[HttpPost]
public ActionResult Create(MoviesActorsViewModel mcvm)
{
_context.mvz.Add(mcvm.mvz);
foreach (var id in mcvm.ids)
{
int id1 = Convert.ToInt32(id);
Actors act = _context.actrs.Find(x => x.Id == id1);
_context.actrs.Add(act);
}
return RedirectToAction("GetView", "Default");
}
#Prince_Walizada as you said, you have a third table which is called a Junction Table and by using EF there is no need to access to this table. because you can directly add any number of the other entity to the current record.
For example (this is pseudo code):
var Movie = MyContext.Movies.Where(P=>Title.Contains("Star war")).FirstOrDefault();
Movie.Actors.Add(new Actor() { Name = "Mike" , ...}
Movie.Actors.Add(new Actor() { Name = "Joe" , ...}
Movie.Actors.Add(new Actor() { Name = "Daniel" , ...}
and you could do this also in reverse:
var Actor = MyContext.Movies.Where(P=>Name.Contains("Mike")).FirstOrDefault();
Actor.Movies.Add(new Movie() { Title = "World of War" , ...}
Actor.Movies.Add(new Movie() { Title = "hobbits" , ...}
Actor.Movies.Add(new Movie() { Title = "toy story" , ...}
As you see, you don't need to know about that third table.

Unable to bind selectlistitem to model property

I have a couple of classes like below -
public class P
{
public int Id { get; set; }
public virtual ICollection<PDetail> PDetails { get; set; }
}
public class PDetail
{
public int Id { get; set; }
public int Type { get; set; }
public double Price { get; set; }
}
Now, in my View, I am displaying it as -
#foreach (var detail in Model.PDetails)
{
<div class="row">
<div class="col-sm-6">
#Html.DropDownListFor(m => detail.Type, (IEnumerable<SelectListItem>)ViewData["Types"], "--Type--", htmlAttributes: new { #class = "form-control" })
</div>
<div class="col-sm-6">
#Html.TextBoxFor(m => detail.Price, "", htmlAttributes: new { #class = "form-control", placeholder = "Price" })
</div>
</div>
}
Here, I am able to display detail.Price for each detail object, but detail.Type is not getting selected from ViewData["Types"] dropdownlist.
PS: ViewData["Types"] is just a dictionary of typeIds = {1,2,3...}
Info1
I also tried changing the View to -
#for (int i = 0; i < Model.PDetails.Count(); i++)
{
<div class="row">
<div class="col-sm-6">
#Html.DropDownListFor(m => m.PDetails.ElementAt(i).Type, (IEnumerable<SelectListItem>)ViewData["Types"], "--Type--", htmlAttributes: new { #class = "form-control" })
</div>
</div>
}
But it is still not working. How can I go about fixing it?
Thanks for sticking through my barrage of questions. I was able to reproduce your issue, and after a whole lot of attempts to get it to work, it seems that this may just be a bug in the MVC framework that hasn't been fixed in over 4 years.
This answer provides two workarounds:
https://stackoverflow.com/a/3529347/1945651
One involves using a somewhat verbose bit of code to manually add the value to the ModelState.
The other requires your list of items to be indexable with square brackets (e.g. an array or IList/IList<T>), and then involves adding the current value as a default value in the SelectList passed to the HTML helper:
#for (int i = 0; i < Model.PDetails.Count(); i++)
{
<div class="row">
<div class="col-sm-6">
#Html.DropDownListFor(m => m.PDetails[i].Type,
new SelectList(ViewData["Types"] as IEnumerable,
"Value", "Text", Model.PDetails[i].Text),
"--Type--",
htmlAttributes: new { #class = "form-control" })
</div>
</div>
}
Could you give that a try?

How to get dynamic dropdownlist selected value

I am new to MVC and using MVC4 for project.
Here is the piece of code in view -
#model SomeModel
#{
for (var i = 0; i < Model.NumberOfQuestions; i++)
{
<div class="ques">
<div class="leftCol">
<label>#Resources.Enroll.Question</label>
</div>
<div class="rightCol">
#Html.DropDownListFor(m => m.Question, Model.Questions, new { id = "ddlQuestion" + i, #data_native_menu = "false", onchange = "SelectedIndexChanged(id)" })
#Html.ValidationMessageFor(m => m.Question)
</div>
<div class="clear" />
<div id="#("customQuestion" + i)" class="hide">
<div class="leftCol">
<label>#Resources.Enroll.CustomQuestion</label>
</div>
<div class="rightCol">
#Html.TextBoxFor(m => m.CustomQuestion, new { id = "txtCustomQues" + i })
#Html.ValidationMessageFor(m => m.CustomQuestion)
</div>
</div>
<div class="clear" />
<div class="leftCol">
<label>#Resources.Enroll.Answer</label>
</div>
<div class="rightCol">
#Html.TextBoxFor(m => m.Answer, new { id = "txtAnswer" + i })
#Html.ValidationMessageFor(m => m.Answer)
</div>
<div class="clear" />
</div>
}
}
The problem here is I'm not able to get some way of managing selected value for all dropdownlist and passing them to controller.
I am able to get single value retained in Question which is a public property in Model. But I am not getting how to do for all dynamically.
Can you please guide me how to do same?
Create a view model that represents the questions you are going to select i.e.
public class QuestionViewModel
{
public string QuestionId { get; set; }
}
Then add them to your existing model, without seeing your current one it should resemble this:
public class QuestionsViewModel
{
public QuestionsViewModel()
{
SelectedQuestions = new List<QuestionViewModel>();
}
public List<SelectListItem> QuestionsSelectList { get; set; }
public List<QuestionViewModel> SelectedQuestions { get; set; }
}
Use indexing in your for loop with the count of the Questions. The important bit is how the QuestionId is used by the model binder to send it back in the post:
#for(var i = 0; i < Model.SelectedQuestions.Count; i++)
{
#Html.DropDownListFor(m => m.SelectedQuestions[i].QuestionId, Model.QuestionsSelectList as List<SelectListItem>, "Select..", new { #data_native_menu = "false", onchange = "SelectedIndexChanged(id)" })
}
When the form is submitted you will have a collection of selected questions i.e.
var selectedQuestion1 = model.SelectedQuestions[0].QuestionId;

Displaying all data in MVC view

This is my first MVC project from scratch and I'm trying to display multiple repeating record data in the view when it first loads and then allow the user to edit the fields on the same page when the edit button is clicked and save the data for that specific record. I have some of the data showing, but i feel like I'm going about it the wrong way.
This is my GeneRuleViewModel.cs
public class GeneRuleViewModel
{
public virtual IEnumerable<GeneRule> GeneRules { get; set; }
public virtual IEnumerable<GeneGroup> GeneGroups { get; set; }
public List<KeyValuePair<int, string>> RuleDataStarDesignation { get; set; }
public List<KeyValuePair<int, IEnumerable<SelectListItem>>> RuleDataPhenotype { get; set; }
public List<KeyValuePair<int, bool>> RuleDataClinicallySignificant { get; set; }
[DisplayName("Star Designation:")]
public string StarDesignation { get; set; }
[DisplayName("Phenotype:")]
public string SelectedPhenotype { get; set; }
[DisplayName("ClinicallySignificant?")]
public bool ClinicallySignificant { get; set; }
}
I used a KeyValuePair so that when looping through the items in the view I could know which value belonged to the specific GeneRule_ID
This is my Index() method in the GeneRuleController.cs where I am populating the KeyValuePairs from the repository
public ActionResult Index()
{
var geneRules = generuleRepository.GetGeneRules();
var geneGroups = generuleRepository.GetGeneGroups();
List<KeyValuePair<int, string>> ruleStarDesignation = new List<KeyValuePair<int, string>>();
List<KeyValuePair<int, IEnumerable<SelectListItem>>> rulePhenotype = new List<KeyValuePair<int, IEnumerable<SelectListItem>>>();
List<KeyValuePair<int, bool>> ruleClinicallySignificant = new List<KeyValuePair<int, bool>>();
foreach (var rule in geneRules)
{
rulePhenotype.Add(new KeyValuePair<int, IEnumerable<SelectListItem>>((int)rule.GeneRule_ID, generuleRepository.GetRulePhenotypes(rule)));
ruleStarDesignation.Add(new KeyValuePair<int, string>((int)rule.GeneRule_ID, generuleRepository.GetRuleStarDesignation(rule)));
ruleClinicallySignificant.Add(new KeyValuePair<int, bool>((int)rule.GeneRule_ID, generuleRepository.GetRuleClinicalSignificance(rule)));
}
var generuleViewModel = new GeneRuleViewModel();
generuleViewModel.GeneRules = geneRules;
generuleViewModel.GeneGroups = geneGroups;
generuleViewModel.RuleDataStarDesignation = ruleStarDesignation;
generuleViewModel.RuleDataPhenotype = rulePhenotype;
generuleViewModel.RuleDataClinicallySignificant = ruleClinicallySignificant;
return View(generuleViewModel);
}
This is my Index.cshtml where I am looping through each GeneGroups and GeneRules to display the data
<div id="generulesgrid">
<span class="glyphicon glyphicon-filter"></span> <span class="h4">Rule Filter</span>
<div class="btn-group rulefilter">
<button type="button" class="filter btn btn-default" data-filter="all">Show All</button>
#foreach (var geneGroup in Model.GeneGroups) {
<button type="button" class="filter btn btn-default" data-filter="#Html.DisplayFor(x => geneGroup.GeneGroup_NM)">#Html.DisplayFor(x => geneGroup.GeneGroup_NM)</button>
}
</div>
#foreach (var geneGroup in Model.GeneGroups) {
<div class="mix #Html.DisplayFor(x => geneGroup.GeneGroup_NM)">
<div class="row">
<div class="col-md-12">
<div class="page-header">
<span class="glyphicon glyphicon-list"></span> <span class="h4">Gene Rules for <small>#Html.DisplayFor(x => geneGroup.GeneGroup_NM)</small></span>
</div>
</div>
</div>
<div class="row">
#foreach(var geneRule in Model.GeneRules.Where(x => x.GeneGroup_ID == geneGroup.GeneGroup_ID))
{
<div class="col-md-4">
#using (Html.BeginForm(null, "generule", FormMethod.Post, new { #class = "form-horizontal", #role = "form" }))
{
<div class="panel panel-default">
<div class="panel-heading">
#Html.DisplayFor(x=> geneRule.GeneRule_NM) <span class="glyphicon glyphicon-edit pull-right editRule" data-toggle="tooltip" title="Edit Rule"></span>
</div>
<div class="panel-body">
<div class="form-group">
#Html.LabelFor(x => x.StarDesignation, new { #class = "col-md-4 control-label" })
<div class="col-md-8">
#Html.TextBoxFor(x => x.StarDesignation, new {#Value = Model.RuleDataStarDesignation.Where(x => x.Key == geneRule.GeneRule_ID).FirstOrDefault().Value, #class = "form-control", #placeholder = "Enter Star Designation"})
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => x.SelectedPhenotype, new { #class = "col-md-4 control-label" })
<div class="col-md-8">
#Html.DropDownListFor(x=>x.SelectedPhenotype,Model.RuleDataPhenotype.Where(x => x.Key == geneRule.GeneRule_ID).FirstOrDefault().Value,"select phenotype",new {#id = "generule_" + geneRule.GeneRule_ID + "_phenotype", #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Rule Definition","Rule Definition:",new { #class = "col-md-4 control-label" })
<div class="col-md-8">
</div>
</div>
<div class="form-group">
<div class="checkbox">
<label>
#Html.CheckBoxFor(x=> x.ClinicallySignificant, Model.RuleDataClinicallySignificant.Where(y => y.Key == geneRule.GeneRule_ID).FirstOrDefault().Value)
</label>
</div>
</div>
</div>
</div>
}
</div>
}
</div>
</div>
}
</div>
As I said, I feel as though that I'm going about this the wrong way, so any help/advice would be greatly appreciated.
It looks decent to me, my approach would have been a bit different; I would have create a partial view for each sub-list in the model that way each partial view takes a simple strongly typed list.
However, your way can also work. Keep in mind (lots of MVC rookies make this mistake), your ViewModel does not have to match the model you bind to when you submit changes.
If you want to be even more slick, you can use AJAX and avoid complicated binding later (but you will have to set up the AJAX which takes some time also).
Edit: If you want the easiest approach, put an edit button with a proper id beside each item you wish to edit, this makes it super-easy to find the item you are editing.
Edit 2: Some nice example here: How to bind multiple textbox with ViewModel array string property?

mvc3 model uses list - not storing to database

This is my first MVC3 project and thought it'd be a bit simpler to accomplish this, but I've had a lot of issues. This seems to be the one trouble for which I've not encountered a solution. Posting here as a last resort.
My issue is that the Ingredients list never seems to populate in the database when a new Recipe is created. I've even tried hard-coding a list in the controller when the rest of the data is saved, but it still doesn't do anything. As far as I can tell, there's not even a field for Ingredients in the DB anywhere. Can anyone point out what I'm doing wrong? Much thanks.
Model:
public class Recipe
{
public int ID { get; set; }
[Required]
public string Title { get; set; }
[Required]
[Display(Name = "Type of Meal")]
public int TypeID { get; set; }
[Required]
public string Instructions { get; set; }
[Display(Name = "Submitted By")]
public string UserName { get; set; }
public IList<string> Ingredients { get; set; }
public virtual MealType Type { get; set; }
}
Create View:
#model final.Models.Recipe
#{
ViewBag.Title = "Recipe Finder - New Recipe";
}
<h2>New Recipe</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">
//adds an ingredient field on the fly
var numIngredients = 0;
function addIngredient() {
$('#ingredientlist').append('<tr><td><input type="text" name="Ingredients[' + numIngredients++ + ']" value="' + $('#AddIngredient').val() + '" readonly="true" tabindex="-1" /></tr></td>');
$('#AddIngredient').val('');
$('#AddIngredient').focus();
}
function onKeyPress(e) {
var keycode;
if (window.event) {
keycode = window.event.keyCode;
}
else if (e) {
keycode = e.which;
}
else {
return true;
}
//for addingredient field, add ingredient and not submit
// else mimic submit
if (keycode == 13) {
if (document.activeElement.id == "AddIngredient") {
addIngredient();
return false;
}
document.getElementById('btnSubmit').click();
}
return true;
}
//intercepts form submit instead of using submit button to disable addingredient textbox
// this prevents the value/field from posting
function preSubmit() {
$('#AddIngredient').attr('disabled', 'true');
document.getElementsByTagName('form')[0].submit();
}
//intercepts users pressing the enter key
if (document.layers) document.captureEvents(Event.KEYPRESS);
document.onkeypress = onKeyPress;
</script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>by #User.Identity.Name</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TypeID, "Type")
</div>
<div class="editor-field">
#Html.DropDownList("TypeID", String.Empty)
#Html.ValidationMessageFor(model => model.TypeID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Ingredients)
</div>
<div class="editor-field">
#Html.TextBox("AddIngredient")
<input type="button" value="Add Ingredient" onclick="addIngredient()" tabindex="-1" />
<table id="ingredientlist">
</table>
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Instructions)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Instructions, new { rows = "7", cols = "77" })
#Html.ValidationMessageFor(model => model.Instructions)
</div>
#Html.HiddenFor(model => model.UserName)
<p>
<input type="button" value="Submit" onclick="preSubmit()" id="btnSubmit" />
</p>
</fieldset>
}
Controller:
[HttpPost]
public ActionResult Create(Recipe recipe)
{
if (ModelState.IsValid)
{
db.Recipes.Add(recipe);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.TypeID = new SelectList(db.MealTypes, "ID", "Type", recipe.TypeID);
return View(recipe);
}
The POST fields I can see send all the information successfully, as seen below, I'm not sure what the issue is, or at this point what I haven't already tried.
Title:test recipe
TypeID:2
Ingredients[0]:test0
Ingredients[1]:test1
Ingredients[2]:test2
Ingredients[3]:test3
Instructions:this is a test
UserName:tym
You may want to check this page about storing a list of strings associated with an entity.

Categories