Model not retaining value in MVC3 on Post - asp.net-mvc

I'm working a viewmodel (vm) for creating a new wine. I assign the ProducerID value to the vm on the get based on the user's profile. I can see the ProducerID value in the view when it is rendered in the view. The user cannot choose or edit this value unless they are in the admin role (i'm not testing with that role). My issue is the ProducerID always comes back on the POST as 0. I don't know what I'm missing as my other selected options in the view come back fine.
I've tried to put a new unique name in the vm itself, but that didn't hold a value either. I've look around and found some other people with similar issues, but none of their solutions have helped. Any assistance on this would be awesome. Thanks!
viewmodel:
{
public Wine Wine { get; set; }
public VOAVIRequest VOAVIRequest { get; set; }
public bool IsRequest { get; set; }
public SelectList VarTypes { get; set; }
public SelectList Origins { get; set; }
public SelectList Apps { get; set; }
public SelectList Vintages { get; set; }
public SelectList Importers { get; set; }
public NewWineViewModel()
{
this.Wine = new Wine();
}
}
wine model:
public class Wine :Updater
{
public int WineID { get; set; }
//public int WineTypeID { get; set; }
[Display(Name = "Varietal/Type")]
public int VarTypeID { get; set; }
[Display(Name = "Origin")]
public int OriginID { get; set; }
[Display(Name = "Appellation")]
public int AppID { get; set; }
[Display(Name = "Vintage")]
public int VintageID { get; set; }
[Display(Name = "Importer")]
public int? ImporterID { get; set; }
public int ProducerID { get; set; }
public string Designate { get; set; }
[Display(Name = "Drink Window")]
public string DrinkWindow { get; set; }
public string Body { get; set; }
public string SKU { get; set; }
[Display(Name = "Case Production")]
public double CaseProduction { get; set; }
[Display(Name = "Alcohol Content")]
public double AlcoholContent { get; set; }
public string Winemaker { get; set; }
[Display(Name = "Consulting Winemaker")]
public string ConsultWinemaker { get; set; }
public bool Sustainable { get; set; }
public bool Kosher { get; set; }
public bool Organic { get; set; }
public bool Biodynamic { get; set; }
public bool SalmonSafe { get; set; }
public Boolean Active { get; set; }
public virtual WineType WineType { get; set; }
public virtual VarType VarType { get; set; }
public virtual Origin Origin { get; set; }
public virtual App App { get; set; }
public virtual Vintage Vintage { get; set; }
public virtual Importer Importer { get; set; }
public virtual Producer Producer { get; set; }
public virtual ICollection<Review> Reviews { get; set; }
public virtual ICollection<Doc> Docs { get; set; }
public IEnumerable<SelectListItem> BodyList { get; set; }
//for dropdownlist binding
//public IEnumerable<VarType> VarTypes { get; set; }
//public IEnumerable<Origin> Origins { get; set; }
//public IEnumerable<App> Apps { get; set; }
//public IEnumerable<Vintage> Vintages { get; set; }
//public IEnumerable<Importer> Importers { get; set; }
//public IEnumerable<Producer> Producers { get; set; }
public Wine()
{
var BodyList = new List<SelectListItem>()
{
new SelectListItem {Value="", Text="Please select wine body"},
new SelectListItem {Value="", Text="Light-bodied"},
new SelectListItem {Value="", Text="Light to Medium-bodied"},
new SelectListItem {Value="", Text="Medium-bodied"},
new SelectListItem {Value="", Text="Medium to Full-bodied"},
new SelectListItem {Value="", Text="Full-bodied"},
new SelectListItem {Value="", Text="Very Full-bodied"}
};
this.BodyList = BodyList;
}
public virtual String Name {
get {
string sName = string.Empty;
int iVintage;
if (!int.TryParse(this.Vintage.Name.Trim(), out iVintage))
{
sName = iVintage.ToString();
}
if (!string.IsNullOrEmpty(this.Designate))
{
sName = sName + " " + this.Producer.Name + " " + this.Designate + " " + this.VarType.Name;
}
else
{
sName = sName + " " + this.Producer.Name + " " + this.VarType.Name;
}
return sName;
}
}
}
controller:
public ActionResult Create()
{
NewWineViewModel nw = new NewWineViewModel();
nw.VarTypes = new SelectList(db.VarTypes, "VarTypeID", "Name").Default("Select a Varietal/Type", "0");
nw.Origins = new SelectList(db.Origins, "OriginID", "Name").Default("Select an Origin", "0");
nw.Apps = new SelectList(db.Apps, "AppID", "Name").Default("Select an Appellation", "0");
nw.Vintages = new SelectList(db.Vintages, "VintageID", "Name").Default("Select a Vintage", "0");
nw.Importers = new SelectList(db.Importers, "ImporterID", "Name").Default("Select an Importer", "0");
// keep dynamic
if (User.IsInRole("producer"))
{
Producer currentProd = db.ProducerUsers.Find(Membership.GetUser().ProviderUserKey).Producer;
nw.Wine.ProducerID = currentProd.ProducerID;
ViewBag.ProducerName = currentProd.Name;
ViewBag.ProducerID = currentProd.ProducerID;
}
else
{
ViewBag.ProducerSelect = new SelectList(db.Producers, "ProducerID", "Name");
}
ViewData.Model = nw;
return View();
}
//
// POST: /Wine/Create
[HttpPost]
//[Authorize(Roles = "admin, producereditor")]
public ActionResult Create(NewWineViewModel nw)
{
if (ModelState.IsValid)
{
nw.Wine.Active = nw.IsRequest ? false : true;
nw.Wine.ImporterID = nw.Wine.ImporterID == 0 ? null : nw.Wine.ImporterID;
nw.Wine.CreatedBy = this.User.Identity.Name;
nw.Wine.CreatedOn = DateTime.Now;
db.Wines.Add(nw.Wine);
db.SaveChanges();
if (nw.IsRequest)
{
nw.VOAVIRequest.WineID = nw.Wine.WineID;
db.VOAVIRequests.Add(nw.VOAVIRequest);
RedirectToAction("Requested");
//redirect to "Request Submitted" page for new wines
}
return RedirectToAction("Details", nw.Wine.WineID);
}
ViewBag.VarTypeID = new SelectList(db.VarTypes, "VarTypeID", "Name").Default("Select a Varietal/Type", nw.Wine.VarTypeID.ToString());
ViewBag.OriginID = new SelectList(db.Origins, "OriginID", "Name").Default("Select an Origin", nw.Wine.OriginID.ToString());
ViewBag.AppID = new SelectList(db.Apps, "AppID", "Name").Default("Select an Appellation", nw.Wine.AppID.ToString());
ViewBag.VintageID = new SelectList(db.Vintages, "VintageID", "Name").Default("Select a Vintage", nw.Wine.VintageID.ToString());
ViewBag.ImporterID = new SelectList(db.Importers, "ImporterID", "Name").Default("Select an Importer", nw.Wine.ImporterID.ToString());
if (User.IsInRole("producer"))
{
Producer currentProd = db.ProducerUsers.Find(Membership.GetUser().ProviderUserKey).Producer;
ViewBag.ProducerID = currentProd.ProducerID;
ViewBag.ProducerName = currentProd.Name;
}
else
{
ViewBag.ProducerSelect = new SelectList(db.Producers, "ProducerID", "Name" ,nw.Wine.ProducerID);
}
return View(nw);
}
view:
#model vf2.ViewModels.NewWineViewModel
#{
ViewBag.Title = "Create a Wine";
}
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
if (User.IsInRole("admin"))
{
<div class="editor-label">
#Html.LabelFor(m => m.Wine.ProducerID, "Producer")
</div>
<div class="editor-field">
#Html.DropDownListFor(m => m.Wine.ProducerID, ViewBag.ProducerSelect as SelectList, "Select a Varietal/Type")
#*#Html.DropDownList("ProducerSelect", String.Empty)*#
</div>
}
else
{
<h3>#ViewBag.ProducerName</h3>
}
#Html.HiddenFor(m => m.IsRequest)
<table>
<tr>
<td>#Html.LabelFor(m => m.Wine.VarTypeID, "VarType")
</td>
<td>
<div class="voavi-select">
#Html.DropDownListFor(m => m.Wine.VarTypeID, Model.VarTypes, new { #class = "chzn-select" })
</div>
#Html.TextBoxFor(m => m.VOAVIRequest.VarType, new { style = "display: none;", #class = "voavignore" })
<a id="lnkNewVar" class="filetypes" href="#">New Varietal?</a> #* #Html.ValidationMessageFor(m => m.VOAVIRequest.VarType)*#
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.OriginID, "Origin")
</td>
<td>
<div class="voavi-select">
#Html.DropDownListFor(m => m.Wine.OriginID, Model.Origins, new { #class = "chzn-select" })
</div>
<a id="lnkNewOrigin" class="filetypes" href="#">New Origin?</a>
#Html.TextBoxFor(m => m.VOAVIRequest.Origin, new { style = "display: none;", #class = "voavignore" })
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.AppID, "App")
</td>
<td>
<div class="voavi-select">
#Html.DropDownListFor(m => m.Wine.AppID, Model.Apps, new { #class = "chzn-select" })
</div>
<a id="lnkNewApp" class="filetypes" href="#">New Varietal?</a>
#Html.TextBoxFor(m => m.VOAVIRequest.App, new { style = "display: none;", #class = "voavignore" })
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.VintageID, "Vintage")
</td>
<td>
<div class="voavi-select">
#Html.DropDownListFor(m => m.Wine.VintageID, Model.Vintages, new { #class = "chzn-select" })
</div>
<a id="lnkNewVintage" class="filetypes" href="#">New Varietal?</a>
#Html.TextBoxFor(m => m.VOAVIRequest.Vintage, new { style = "display: none;", #class = "voavignore" })
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Designate)
</td>
<td>
#Html.EditorFor(m => m.Wine.Designate)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.DrinkWindow)
</td>
<td>
#Html.EditorFor(m => m.Wine.DrinkWindow)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Body)
</td>
<td>
#Html.DropDownListFor(m => m.Wine.Body, new SelectList(Model.Wine.BodyList, "Value", "Text"), new { #class = "chzn-select" })
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.ImporterID, "Importer")
</td>
<td>
<div class="voavi-select">
#Html.DropDownListFor(m => m.Wine.ImporterID, Model.Importers, new { #class = "chzn-select" })</div>
<a id="lnkNewImporter" class="filetypes" href="#">New Varietal?</a>
#Html.TextBoxFor(m => m.VOAVIRequest.Importer, new { style = "display: none;" })
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.SKU)
</td>
<td>
#Html.EditorFor(m => m.Wine.SKU)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.CaseProduction)
</td>
<td>
#Html.EditorFor(m => m.Wine.CaseProduction)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.AlcoholContent)
</td>
<td>
#Html.EditorFor(m => m.Wine.AlcoholContent)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Winemaker)
</td>
<td>
#Html.EditorFor(m => m.Wine.Winemaker)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.ConsultWinemaker)
</td>
<td>
#Html.EditorFor(m => m.Wine.ConsultWinemaker)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Sustainable)
</td>
<td>
#Html.EditorFor(m => m.Wine.Sustainable)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Kosher)
</td>
<td>
#Html.EditorFor(m => m.Wine.Kosher)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Organic)
</td>
<td>
#Html.EditorFor(m => m.Wine.Organic)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.Biodynamic)
</td>
<td>
#Html.EditorFor(m => m.Wine.Biodynamic)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m => m.Wine.SalmonSafe)
</td>
<td>
#Html.EditorFor(m => m.Wine.SalmonSafe)
</td>
</tr>
</table>
<p>
<input type="submit" value="Create" />
</p>
}

ProducerID isn't being populated because it looks like it's not being posted back with the form. If it's not part of your route, you need to persist it in a hidden field:
#Html.HiddenFor(m => m.ProducerID)

Related

Issue on retrieving value from DropDownListFor

I have a situation where I would like administrators to re-order questions to however they like, however, I have an issue on retrieving the value selected from the "DropDownListFor" from my form to my controller.
Placing the breakpoint at "Debug.WriteLine(MV.Count), the variable "SetNewValue" returns null in my controller
So what is the proper way to retrieve the new value that is selected and my default selected value from my DropDownListFor, as well as the current question number to my controller upon "onchange = this.form.submit()"?
I know the [HttpPost] Controller part is not a proper method to swap the questions, it is there for me to see whether the variables I have set do return the values that are sent from the DropDownListFor upon "onchange" form submit.
Any form of help is appreciated, as I am a beginner in MVC.
My View
#model IList<AppXamApplication.Models.EditQuestionsAndAnswersViewModel>
#{
ViewBag.Title = "EditQuestionsPage2";
}
<h4>Edit Your Questions Here</h4>
#using (Html.BeginForm("EditQuestionsPage2", "ExamAdmin", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<table id="tblQuestions" border="0" style="border:none">
#for (int i = 0; i < Model.Count; i++)
{
if (Model[i].TypeOfQuestion == "Open Ended")
{
<tr>
<td>
#Html.DropDownListFor(m => m[i].SetNewValue, new SelectList(Model[i].TotalNoQuestions, "Value", "Text", Model[i].ToSetPreSelectValue), new { #Name = "CurrentQnAction", onchange = "this.form.submit();" })
#Html.HiddenFor(m => m[i].CurrentQuestionNumber, new { CurrentQnNoID = Model[i].CurrentQuestionNumber })
</td>
<td> </td>
<td> </td>
<td>
#Html.ActionLink("Delete Question", "EditQuestionsPage2", new { Question_ID = Model[i].QuestionID, #class = "form-control" })
</td>
</tr>
<tr>
<td>
<b>Question Type: #Html.DisplayFor(m => m[i].TypeOfQuestion, new { #class = "form-control" }) </b>
</td>
</tr>
<tr>
<td>
#Html.EditorFor(m => m[i].QuestionsAsked, new { #class = "form-control" })
</td>
</tr>
<tr>
<td>
<br />
<br />
</td>
</tr>
}
}
</table>
}
Edited: My Model
public class EditQuestionsAndAnswersViewModel
{
//Questions
public string QuestionID { get; set; }
public string TypeOfQuestion { get; set; }
public string ExamID { get; set; }
public string QuestionsAsked { get; set; }
public string UserID { get; set; }
public int? OrderingQuestions { get; set; }
public int? CurrentQuestionNumber { get; set; }
public string SetNewValue { get; set; }
public int? ToSetPreSelectValue{ get; set; }
public IList<SelectListItem> TotalNoQuestions { get; set; }
public IList<EditAnswers> PossibleAnswers { get; set; }
public string AnswerID { get; set; }
public string AnswerText { get; set; }
}
Edited: My Controllers
[HttpGet]
public ActionResult EditQuestionsPage2()
{
if (ModelState.IsValid)
{
using (var ctx = new AppXamApplicationEntities())
{
var CurrentExamID2 = (string)Session["CurrentExamID2"];
string CurrentExamID2_string = Convert.ToString(CurrentExamID2);
var query = ctx.Questions.Where(x => x.ExamID.Equals(CurrentExamID2_string))
.Select(x => new EditQuestionsAndAnswersViewModel()
{
QuestionID = x.QuestionID,
TypeOfQuestion = x.TypeOfQuestion,
ExamID = x.ExamID,
QuestionsAsked = x.QuestionsAsked,
UserID = x.UserID,
ToSetPreSelectValue= x.QuestionOrder,
// To Order the questions in ascending order
OrderingQuestions = x.QuestionOrder,
// To Display Current Question Number
CurrentQuestionNumber = x.QuestionOrder,
// To Display the dropdownlist as well as set the default selected value to be displayed for each question in the dropdownlist
TotalNoQuestions = ctx.Questions.Where (v=> v.ExamID.Equals(x.ExamID)).Select(v => new SelectListItem
{
Value = v.QuestionOrder.ToString(),
Text = v.QuestionOrder.ToString(),
}).ToList(),
PossibleAnswers = x.Answers.Where(y => y.QuestionID.Equals(x.QuestionID)).Select(y => new EditAnswers()
{
AnswerID = y.AnswerID,
AnswerText = y.AnswerText
}).ToList()
}).ToList().AsQueryable();
var queryOrdered = query.OrderBy(x=> x.CurrentQuestionNumber).ToList();
return View(queryOrdered);
}
}
return View();
}
[HttpPost]
public ActionResult EditQuestionsPage2(string action, string CurrentQnAction, int? CurrentQnNoID, IList<EditQuestionsAndAnswersCollectionModel> MV, string ToRetrieveSelectedValue, AddQuestions _model)
{
if (ModelState.IsValid)
{
if (CurrentQnNo!= null)
{
//Breakpoint placed over here
Debug.WriteLine(MV.Count);
}
}
return View();
}

ASP.Net MVC: How to associate hobbies with each student

I am facing trouble to create association between student and hobbies. i am showing my data though editable webgrid. webgrid has textboxes for name, dropdown for country selection and checkboxes for hobbies.
i want when user select each student hobbies...may be one or multiple and press submit button then i should be able to know each student's hobbies from student view model.
due to lack of knowledge i am not being able to do it.
this how my UI looks
This way i am generation checkboxes in each row webgrid.
grid.Column(header: "Hobbies",
format: #<text>
#for (var i = 0; i < Model.Hobbies.Count; i++)
{
<div class="checkbox">
#Html.HiddenFor(m => m.Hobbies[i].ID)
#Html.HiddenFor(m => m.Hobbies[i].Name)
#Html.CheckBoxFor(m => m.Hobbies[i].Checked)
#Html.LabelFor(m =>m.Hobbies[i].ID, Model.Hobbies[i].Name)
</div>
}
</text>)
my full razor code
#model MVCCRUDPageList.Models.StudentListViewModel
#{
ViewBag.Title = "Index";
}
<h2>Student View Model</h2>
#using (Html.BeginForm("Index", "WebGridMoreControls", FormMethod.Post))
{
var grid = new WebGrid(Model.Students, canSort: false, canPage: false);
var rowNum = 0;
var SelectedHobbies = 0;
<div id="gridContent" style=" padding:20px; ">
#grid.GetHtml(
tableStyle: "table",
alternatingRowStyle: "alternate",
selectedRowStyle: "selected",
headerStyle: "header",
columns: grid.Columns
(
grid.Column(null, header: "Row No", format: item => rowNum = rowNum + 1),
grid.Column("ID", format: (item) => #Html.TextBoxFor(m => m.Students[rowNum - 1].ID, new { #class = "edit-mode" })),
grid.Column("Name", format: (item) => #Html.TextBoxFor(m => m.Students[rowNum - 1].Name, new { #class = "edit-mode" })),
grid.Column("Country", format: (item) =>
#Html.DropDownListFor(x => x.Students[rowNum - 1].CountryID,
new SelectList(Model.Country, "ID", "Name", item.CountryID),
"-- Select Countries--", new { id = "cboCountry", #class = "edit-mode" })),
grid.Column(header: "Hobbies",
format: #<text>
#for (var i = 0; i < Model.Hobbies.Count; i++)
{
<div class="checkbox">
#Html.HiddenFor(m => m.Hobbies[i].ID)
#Html.HiddenFor(m => m.Hobbies[i].Name)
#Html.CheckBoxFor(m => m.Hobbies[i].Checked)
#Html.LabelFor(m =>m.Hobbies[i].ID, Model.Hobbies[i].Name)
</div>
}
</text>)
))
<input type="submit" value="Submit" />
</div>
}
My controller and action code
public class WebGridMoreControlsController : Controller
{
// GET: WebGridMoreControls
public ActionResult Index()
{
StudentListViewModel osvm = new StudentListViewModel();
return View(osvm);
}
[HttpPost]
public ActionResult Index(StudentListViewModel oStudentListViewModel)
{
return View(oStudentListViewModel);
}
}
My ViewModel code
public class StudentListViewModel
{
public IList<Student> Students { get; set; }
public List<Country> Country { get; set; }
public IList<Hobby> Hobbies { get; set; }
public StudentListViewModel()
{
Students = new List<Student>
{
new Student{ID=1,Name="Keith",CountryID=0},
new Student{ID=2,Name="Paul",CountryID=2},
new Student{ID=3,Name="Sam",CountryID=3}
};
Country = new List<Country>
{
new Country{ID=1,Name="India"},
new Country{ID=2,Name="UK"},
new Country{ID=3,Name="USA"}
};
Hobbies = new List<Hobby>
{
new Hobby{ID=1,Name="Football",Checked=false},
new Hobby{ID=2,Name="Hocky",Checked=false},
new Hobby{ID=3,Name="Cricket",Checked=false}
};
}
}
My Model code
public class Student
{
public int ID { get; set; }
[Required(ErrorMessage = "First Name Required")]
public string Name { get; set; }
//[Required(ErrorMessage = "Last Name Required")]
//public string LastName { get; set; }
public int CountryID { get; set; }
}
public class Country
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Hobby
{
public int ID { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
please help me what i am trying to achieve. thanks
EDIT 1
#for (var i = 0; i < Model.Hobbies.Count; i++)
{
<div class="checkbox">
#Html.HiddenFor(m => m.Hobbies[i].ID)
#Html.HiddenFor(m => m.Hobbies[i].Name)
#Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].ID)
#Html.CheckBoxFor(m => m.Students[rowNum - 1].Hobbies[i].Checked)
#*#Html.CheckBoxFor(m => m.Hobbies[i].Checked)*#
#Html.LabelFor(m =>m.Hobbies[i].ID, Model.Hobbies[i].Name)
</div>
}
I could restructure my view model,model and razor view code. here i like to give my updated code which is working fine.
This way i generate checkboxes in forloop.
grid.Column(header: "Hobbies",
format: #<text>
#for (var i = 0; i < Model.Students.FirstOrDefault().Hobbies.Count; i++)
{
<div class="checkbox">
#Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].ID)
#Html.HiddenFor(m => m.Students[rowNum - 1].Hobbies[i].Name)
#Html.CheckBoxFor(m => m.Students[rowNum - 1].Hobbies[i].Checked)
#Html.LabelFor(m => m.Students[rowNum - 1].Hobbies[i].Name, Model.Students.FirstOrDefault().Hobbies[i].Name)
</div>
}
</text>)
view model and model class code
public class StudentListViewModel
{
public IList<Student> Students { get; set; }
public List<Country> Country { get; set; }
public StudentListViewModel()
{
Students = new List<Student>
{
new Student
{
ID=1,Name="Keith",CountryID=0,
Hobbies= new List<Hobby>
{
new Hobby{ID=1,Name="Football",Checked=false},
new Hobby{ID=2,Name="Hocky",Checked=false},
new Hobby{ID=3,Name="Cricket",Checked=false}
}
},
new Student
{
ID=2,Name="Paul",CountryID=2,
Hobbies= new List<Hobby>
{
new Hobby{ID=1,Name="Football",Checked=false},
new Hobby{ID=2,Name="Hocky",Checked=false},
new Hobby{ID=3,Name="Cricket",Checked=false}
}
},
new Student
{
ID=3,Name="Sam",CountryID=3,
Hobbies= new List<Hobby>
{
new Hobby{ID=1,Name="Football",Checked=false},
new Hobby{ID=2,Name="Hocky",Checked=false},
new Hobby{ID=3,Name="Cricket",Checked=false}
}
}
};
Country = new List<Country>
{
new Country{ID=1,Name="India"},
new Country{ID=2,Name="UK"},
new Country{ID=3,Name="USA"}
};
}
}
Model code
public class Student
{
public int ID { get; set; }
[Required(ErrorMessage = "First Name Required")]
public string Name { get; set; }
//[Required(ErrorMessage = "Last Name Required")]
//public string LastName { get; set; }
public int CountryID { get; set; }
public IList<Hobby> Hobbies { get; set; }
}
public class Country
{
public int ID { get; set; }
public string Name { get; set; }
}
public class Hobby
{
public int ID { get; set; }
public string Name { get; set; }
public bool Checked { get; set; }
}
Bit Different way done again
The same UI i also developed with html table. here i am sharing the razor code and rest of the model and model view code is same as before.
#model MVCCRUDPageList.Models.StudentListViewModel
#{
ViewBag.Title = "Index";
}
<h2>CREATE TABULAR UI WITH HTML TABLE</h2>
#using (Html.BeginForm("Index", "HtmlTable", FormMethod.Post))
{
<div class="form-group">
<div class="col-md-12 table-responsive">
<table class="table table-bordered table-hover">
<tr>
<th>
Row No
</th>
<th>
ID
</th>
<th>
Name
</th>
<th>
Country
</th>
<th>
Hobbies
</th>
<th>
Sex
</th>
</tr>
}
#for (int x=0; x<=Model.Students.Count-1;x++)
{
<tr>
<td>
<label>#(x+1)</label>
</td>
<td>
#Html.TextBoxFor(m => m.Students[x].ID)
</td>
<td>
#Html.TextBoxFor(m => m.Students[x].Name)
</td>
<td>
#Html.DropDownListFor(m => m.Students[x].CountryID,
new SelectList(Model.Country, "ID", "Name", Model.Students[x].CountryID),
"-- Select Countries--", new { id = "cboCountry", #class = "edit-mode" })
</td>
<td>
#for (var i = 0; i < Model.Students.FirstOrDefault().Hobbies.Count; i++)
{
<div class="checkbox">
#Html.HiddenFor(m => m.Students[x].Hobbies[i].ID)
#Html.HiddenFor(m => m.Students[x].Hobbies[i].Name)
#Html.CheckBoxFor(m => m.Students[x].Hobbies[i].Checked)
#Html.LabelFor(m => m.Students[x].Hobbies[i].Name, Model.Students[x].Hobbies[i].Name)
</div>
}
</td>
<td>
#for (var i = 0; i < Model.Sex.Count; i++)
{
<div class="checkbox">
#Html.HiddenFor(m => Model.Sex[i].ID)
#Html.HiddenFor(m => Model.Sex[i].SexName)
#Html.RadioButtonFor(m => m.Students[x].SexID, Model.Sex[i].ID)
#Html.LabelFor(m => m.Students[x].SexID, Model.Sex[i].SexName)
</div>
}
</td>
</tr>
}
</table>
</div>
<input type="submit" value="Submit" />
</div>
}
[1]: https://stackoverflow.com/users/3559349/stephen-muecke

Proper way to bind the model to view in MVC?

Im newbie to mvc.I have a menusettings page where user can add menu according to his role.For that I want to create a view.How can I bind the model to view properly so that i can save the settings.My concern is inorder to access ienumerable item in the viewmodel,viewmodel should also be ienumerable.Here i cannot convert the viewmodel to ienumerable.
Any help will be greatly appreciated
ModelClass is
public partial class Role
{
public int Id { get; set; }
public string RoleName { get; set; }
public Nullable<int> ParentID { get; set; }
public virtual ICollection<MenuRole> MenuRoles { get; set; }
}
public partial class Menu
{
public int Id { get; set; }
public string MenuName { get; set; }
public string NavigateUrl { get; set; }
public Nullable<int> ParentID { get; set; }
public virtual ICollection<MenuRole> MenuRoles { get; set; }
}
ViewModel Is
public class MenuRoleVM
{
public int? RoleId { get; set; }
public SelectList RoleList { get; set; }
public IEnumerable<Menu> MenuList { get; set; }
}
My controller is
public class MenuSettingsController : Controller
{
public ActionResult Add()
{
var _menuRoleVM = new MenuRoleVM
{
RoleList = new SelectList(_db.Roles.ToList(), "Id", "RoleName"),
MenuList = _db.Menus
.Where(m => m.NavigateUrl != "#").ToList()
};
return View(_menuRoleVM);
}
}
Below example will help. Here, I have the model ContactModel with properties - FirstName, LastName and Email.
#model IEnumerable<CrazyContacts.Models.ContactModel>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
Thanks for your input #Stephen.
I got the code running by the adding the view as below
#foreach (var item in Model.MenuList.Select((x, i) => new {Data=x,Index=i }))
{
<tr>
<td>#(item.Index+1)</td>
<td>#item.Data.MenuName</td>
</tr>
}

Avoid duplicating the results on viewpage in mvc

I'm creating banking application in MVC 5.
Load table by bank and Load table rows by Bank,
But I cannot figure out do this exactly like above image,
This what I'm getting , it has 10 tables, instead just 2 tables
this is cshtml code for above view
#model IEnumerable<albaraka.Models.ProductApprovals>
#{
ViewBag.Title = "Product_Approvals";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>sadfasf</h2>
<h2>Product Approvals</h2>
#using (Html.BeginForm("Index", "Student", FormMethod.Get))
{
<div> Filter by : Date #Html.TextBox("SearchString", ViewBag.CurrentFilter as string) Filter by : Country #Html.TextBox("SearchString", ViewBag.CurrentFilter as string) <input type="submit" value="Search" /> </div>
}
#foreach (var item in Model)
{
#Html.DisplayNameFor(model => model.SubsidaryName); <p &nbsp /> #Html.DisplayFor(modelItem => item.SubsidaryName);
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ProductNameEn)
</th>
<th>
#Html.DisplayNameFor(model => model.ProdcutNameAr)
</th>
<th>
#Html.DisplayNameFor(model => model.CurrentStatus)
</th>
<th>
Actions
</th>
</tr>
#foreach (var inside in Model)
{
if (inside.Subsidary_ID == item.Subsidary_ID)
{
<tr>
<td>
#Html.DisplayFor(modelItem => inside.ProductNameEn)
</td>
<td>
#Html.DisplayFor(modelItem => inside.ProdcutNameAr)
</td>
<td>
#Html.DisplayFor(modelItem => inside.CurrentStatus)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
}
</table>
}
This is Model class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace albaraka.Models
{
public class ProductApprovals
{
public DateTime SearchDate { get; set; }
public string Country { get; set; }
public string Product_ID { get; set; }
public string Subsidary_ID { get; set; }
public string SubsidaryName { get; set; }
public string ProductNameEn { get; set; }
public string ProdcutNameAr { get; set; }
public string CurrentStatus { get; set; }
}
}
This is Controller class
public ActionResult Product_Approvals()
{
var productApproveResult =(from p in db.AB_Product
join s in db.AB_Subsidary on p.Subsidary_ID equals s.SubsidaryID
select new ProductApprovals
{
Product_ID = p.ProductID,
Subsidary_ID = s.SubsidaryID,
SubsidaryName = s.SubsidaryNameEn,
ProductNameEn = p.ProductTitleEn,
ProdcutNameAr = p.ProductTitleAr,
CurrentStatus = p.Status
}).ToList();
return View(productApproveResult);
}
How to stop this repeating ,appricate if can show a way to this in view page
You need a view model(s) to represent what you want to display in the view. It should be something like
public class BankVM
{
public string SubsidaryName { get; set; }
public IEnumerable<ProductVM> Products { get; set; }
}
public class ProductVM
{
public string ProductNameEn { get; set; }
public string ProdcutNameAr { get; set; }
public string CurrentStatus { get; set; }
}
and pass a collection of BankVM to the view
#model IEnumerable<yourAssembly.BankVM>
#foreach(var bank in Model)
{
<h3>#Html.DisplayFor(m => bank.SubsidaryName)</h3>
<table>
foreach(var product in bank.Products)
{
<tr>
<td>#Html.DisplayFor(m => product.ProductNameEn)</td>
<td>#Html.DisplayFor(m => product.ProductNameAr)</td>
....
</tr>
}
</table>
}
In the controller, you can use a Linq .GroupBy() method to populate your collection of BankVM

Composite ViewModel and UpdateModel

What is missing that restuls in unpopulated values in POST action?
Controller
public ActionResult Index()
{
var productPageViewModel = new ProductPageViewModel();
productPageViewModel.ProductPageCriteria = BuildProductPageCriteriaViewModel();
productPageViewModel.Products = GetProducts(productPageViewModel.ProductPageCriteria);
return View(productPageViewModel);
}
[HttpPost]
public ActionResult Index(ProductPageViewModel productPageViewModel, FormCollection formCollection)
{
// productPageViewModel is not populated with posted values of ProductPageCriteria.CategoryID, ProductPageCriteria.DepartmentID and ProductPageCriteria.PageSize
// formCollection has correct values
// Calling UpdateModel(productPageViewModel); has no affect - makes sense, the framework has already called it
// Calling UpdateModel(productPageViewModel.ProductPageCriteria); populates the values.
// The renderd form has names like CategoryID, DepartmentID unlike ProductPageCriteria.CategoryID, ProductPageCriteria.DepartmentID
// if the top model was passed to all partial views also.
return View(productPageViewModel);
}
Models
public class ProductPageCriteriaViewModel
{
public const int DefaultPageSize = 15;
public ProductPageCriteriaViewModel()
{
Categories = new List<Category>();
Departments = new List<Department>();
PageSize = DefaultPageSize;
}
[Display(Name = "Category")]
public int? CategoryID { get; set; }
[Display(Name = "Department")]
public int DepartmentID { get; set; }
[Display(Name = "Page Size")]
public int? PageSize { get; set; }
public List<Category> Categories { get; set; }
public List<Department> Departments { get; set; }
}
public class ProductPageViewModel
{
public ProductPageViewModel()
{
ProductPageCriteria = new ProductPageCriteriaViewModel();
Products = new List<Product>();
}
public ProductPageCriteriaViewModel ProductPageCriteria { get; set; }
public List<Product> Products { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public Category Category { get; set; }
public Department Department { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
public class Department
{
public int DepartmentID { get; set; }
public string DepartmentName { get; set; }
}
View Index.cshtml
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
#Html.Partial("_ProductCriteria", Model.ProductPageCriteria)
#Html.Partial("_ProductList", Model.Products)
}
Partial View _ProductCriteria.cshtml
#model Mvc3Application4.Models.ProductPageCriteriaViewModel
<fieldset>
<legend>Criteria</legend>
<div class="editor-label">
#Html.LabelFor(model => model.CategoryID)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.Categories, "CategoryID", "CategoryName", Model.CategoryID), "--- All ---")
#Html.ValidationMessageFor(model => model.CategoryID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DepartmentID)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.DepartmentID, new SelectList(Model.Departments, "DepartmentID", "DepartmentName", Model.DepartmentID), "--- All ---")
#Html.ValidationMessageFor(model => model.DepartmentID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PageSize)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.PageSize, new SelectList(new List<int> {10, 15, 20, 25, 50, 100}.Select(n => new {Value = n, Text = n}), "Value", "Text", Model.PageSize), "--- All ---")
#Html.ValidationMessageFor(model => model.PageSize)
</div>
<p>
<input type="submit" value="Search" />
</p>
</fieldset>
Partial View _ProductList.cshtml
#model IEnumerable<Mvc3Application4.Models.Product>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>
ProductName
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ProductID }) |
#Html.ActionLink("Details", "Details", new { id=item.ProductID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ProductID })
</td>
<td>
#item.ProductName
</td>
</tr>
}
</table>
This is off the top of my head and untested, but I believe if you pass the parent model (ProductPageViewModel) to the products criteria partial view, change the partial view to inherit this model, and change the controls to use from model => model.ProductPageCriteria.CategoryID instead of model => model.CategoryID, it should maintain the naming so that UpdateModel can match up the fields with the posted values.
Sorry for the extreme run-on sentence and if this is incorrect I'm sure I'll earn my Peer Pressure badge pretty quickly. :) Hope this helps.

Resources