Model Binding not working with mvc1 - asp.net-mvc

We have very large object called FoodFormViewModel. We go to add page like
FoodFormViewModel foodFormViewModel = new FoodFormViewModel();
return View("Edit", foodFormViewModel);
But when we come to post method like
[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult Edit(FoodFormViewModel objViewModel)
{
SaveProcess(objViewModel);
return View(objViewModel);
}
Our objViewModel properties are all blank. Our FoodFormViewModel definition is
#region Properties
public MealPlannerDataManager MPManager { get; set; }
public Food Food { get; set; }
public SelectList FoodGroupLevel1 { get; set; }
public SelectList FoodGroupLevel2 { get; set; }
public SelectList FoodGroupLevel3 { get; set; }
public SelectList FoodType { get; set; }
public SelectList Company { get; set; }
public SelectList Brand { get; set; }
public SelectList NutritionSource { get; set; }
public SelectList DataSource { get; set; }
public SelectList PlannerSource { get; set; }
public SelectList PublishMonth { get; set; }
public SelectList PublishDay { get; set; }
public SelectList PublishYear { get; set; }
public SelectList TagTypes { get; set; }
public List<CheckBoxInfo> MealTime { get; set; }
public List<CheckBoxInfo> Condition { get; set; }
public List<CheckBoxInfo> Allergens { get; set; }
public List<CheckBoxInfo> Occasions { get; set; }
public List<CheckBoxInfo> Others { get; set; }
public List<CheckBoxInfo> SpecialDiet { get; set; }
public List<CheckBoxInfo> Course { get; set; }
public List<CheckBoxInfo> PrepMethod { get; set; }
public List<CheckBoxInfo> Season { get; set; }
public List<CheckBoxInfo> SkillLevel { get; set; }
public List<CheckBoxInfo> Cuisine { get; set; }
public List<CheckBoxInfo> MealPlan { get; set; }
public List<CheckBoxInfo> Products { get; set; }
public List<CheckBoxInfo> AgeGroup { get; set; }
public FoodNutritionInfo NutrInfo { get; set; }
public FoodNutritionInfo AltNutrInfo { get; set; }
Tag dummyTag = new Tag();
TagType dummyTagType = new TagType();
#endregion Properties
WE couldn't figure out the issue. Any help is highly appreciated.
We are using MVC1 with VS 2008
My view contains 3-4 partial views, i am posting one of the partial view here
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MealPlannerAdmin.Models.ViewModel.FoodFormViewModel>" %>
<%# Import Namespace="MealPlannerAdmin.Models.Objects.HTMLHelpers" %>
<%# Import Namespace="MealPlanner.BusinessObjects.Model" %>
<div id="ValidationSummary" style="position: absolute; margin: 110px 0px 0px 620px;
width: 350px; height: 359px; overflow: auto; border: 0px">
<%=Html.ValidationSummary("Please review all tabs for following errors") %>
</div>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tbody>
<tr>
<td colspan="2">
<div id="foobar" style="color: Red;">
<%=ViewData["CloningMessage"]%></div>
</td>
</tr>
<tr>
<td colspan="2" class="comHead">
<strong>Food Basic Information</strong>
</td>
</tr>
<tr>
<td colspan="2">
<div id="divCloningMessage" class="errMsg">
</div>
</td>
</tr>
<tr>
<td colspan="2">
<div id="divBtnCloneThisFood" style="display: none;">
<input type="button" value="Clone this Food" id="btnCloneThisFood" name="btnCloneThisFood" />
</div>
</td>
</tr>
<tr>
<td width="200" valign="top">
<span id="spanOriginalCreatorLabel"></span>
</td>
<td>
<span id="spanOriginalCreator"></span>
</td>
</tr>
<tr>
<td width="200" valign="top">
<span id="spanClonedByLabel"></span>
</td>
<td>
<span id="spanClonedBy"></span>
</td>
</tr>
<tr>
<td width="200" valign="top">
<label for="lblFoodID">
Food ID:
</label>
</td>
<td>
<span id="spanFoodID" name="spanFoodID">
<%=Model.Food.FoodID%></span>
</td>
</tr>
<tr>
<td valign="top">
<label for="ddlFoodGroupLevel1">
Food Group Level 1: *</label>
</td>
<td>
<%=Html.DropDownList("ddlFoodGroupLevel1", Model.FoodGroupLevel1, new { #class = "dropdown"})%> <%=Html.ValidationMessage("FoodGroupLevel1", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="ddlFoodGroupLevel2">
Food Group Level 2 :
</label>
</td>
<td>
<%=Html.DropDownList("ddlFoodGroupLevel2", Model.FoodGroupLevel2, new { #class = "dropdown" })%> <%=Html.ValidationMessage("FoodGroupLevel2", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="ddlFoodGroupLevel3">
Food Group Level 3:
</label>
</td>
<td>
<%=Html.DropDownList("ddlFoodGroupLevel3", Model.FoodGroupLevel3, new { #class = "dropdown" })%>
</td>
</tr>
<tr>
<td valign="top">
<label for="Food.FoodName">
Food Name: *</label>
</td>
<td>
<%=Html.TextBox("FoodName", Model.Food.FoodName, new { #maxlength = "250" })%> <%=Html.ValidationMessage("FoodName", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="FoodDisplayName">
Food Display Name: *</label>
</td>
<td>
<%=Html.TextBox("FoodDisplayName", Model.Food.FoodDisplayName, new { #maxlength = "250" })%> <%=Html.ValidationMessage("FoodDisplayName", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="ddlFoodType">
Food Type: *</label>
</td>
<td>
<%=Html.DropDownList("ddlFoodType", Model.FoodType, new { #class = "dropdown" })%> <%=Html.ValidationMessage("FoodType", "*")%>
</td>
</tr>
<tr id="rowCompany">
<td valign="top">
<label for="ddlCompany">
<span id="spanCompany" name="spanCompany"></span>
</label>
</td>
<td>
<%=Html.DropDownList("ddlCompany", Model.Company, new { #class = "dropdown" })%> <%=Html.ValidationMessage("Company", "*")%>
</td>
</tr>
<tr id="rowAddCompany">
<td>
</td>
<td>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2" valign="top" class="subHead">
<label for="txtAddCompany">
<span id="spanAddCompany" name="spanAddCompany"></span>
</label>
</td>
</tr>
<tr>
<td>
<%=Html.TextBox("txtAddCompany", string.Empty, new { #id = "txtAddCompany", #maxlength = 100, #boundButton = "btnNewCompany", #catId = Convert.ToInt16(EntityConstants.TagType.Company), #catName = EntityConstants.TagType.Company, #updateEle = "divAgeGroup", #uiUpdateType = "drop-down-list" })%>
<div id="divAddCompanyError" boundbutton="btnNewCompany" class="errHidden">
</div>
<div id="<%=EntityConstants.TagType.Company %>Message" style="display: none; color: Red;">
</div>
</td>
<td>
</td>
</tr>
<tr>
<td>
<%=Html.TextArea("txtAddCompanyDesc", string.Empty, 5, 42, new { #id = "txtAddCompanyDesc", #class = "text-area-classic w374px", #boundButton = "btnNewCompany" })%>
</td>
<td valign="bottom">
<input type="button" value="Add" id="btnNewCompany" />
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td valign="top">
<label for="cblMealTime">
Meal Time:</label>
</td>
<td>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td>
<%=Html.CheckBoxGrid("cblMealTime", Model.MealTime, 4) %>
</td>
<td>
<%=Html.ValidationMessage("Meal", "*")%>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td valign="top">
<label for="ddlNutritionSource">
Nutrition Source: *</label>
</td>
<td>
<%=Html.DropDownList("ddlNutritionSource", Model.NutritionSource, new { #class = "dropdown" })%> <%=Html.ValidationMessage("NutritionSource", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="ddlDataSource">
Data Source: *</label>
</td>
<td>
<%=Html.DropDownList("ddlDataSource", Model.DataSource, new { #class = "dropdown" })%> <%=Html.ValidationMessage("DataSource", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="Display">
Display: *</label>
</td>
<td>
<%=Html.RadioButton("Display", true, Model.Food.Display, new { #id = "DisplayTrue" })%><label>Yes</label>
<%=Html.RadioButton("Display", false, !(Model.Food.Display), new { #id = "DisplayFalse" }) %><label>No</label>
</td>
</tr>
<tr>
<td valign="top">
<label for="Issue">
Issue: *</label>
</td>
<td>
<%=Html.RadioButton("Issue", true, Model.Food.Issue, new {#id="IssueTrue", #onclick= "disableIssueText()"})%><label>Yes</label>
<%=Html.RadioButton("Issue", false, !(Model.Food.Issue), new {#id="IssueFalse", #onclick = "disableIssueText()" })%><label>No</label>
</td>
</tr>
<tr>
<td valign="top">
<label for="IssueDescription">
Describe Issue:
</label>
</td>
<td>
<%=Html.TextArea("IssueDescription", Model.Food.IssueDescription, 4, 75, new { #maxlength = "50", #class = "w500px" })%>
</td>
</tr>
<tr>
<td valign="top">
<label for="FoodDescription">
Description:</label>
</td>
<td>
<%=Html.TextArea("FoodDescription", Model.Food.FoodDescription, 5, 40, new { #maxlength = "50" })%> <%=Html.ValidationMessage("FoodDescription", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="Tags">
Tags:</label>
</td>
<td>
<%=Html.TextArea("Tags", Model.Food.Tags, 5, 40, new { #maxlength = "50" })%> <%=Html.ValidationMessage("Tags", "*")%>
</td>
</tr>
<tr>
<td valign="top">
<label for="Image">
Image:</label>
</td>
<td>
<table>
<tr>
<td>
<%=Html.Image("Img200x200", Model.Food.Img200x200, "Food Image", new { #width = "200", #height = "200" })%>
</td>
</tr>
<tr>
<td>
<div id="browseFile">
<input name="Image" id="Image" type="file" size="45" onchange="document.getElementById('inputTxtFake').value = this.value;"
class="inputImage" />
<!-- fake input to display the path of the selected file : start -->
<input name="inputTxtFake" type="text" id="inputTxtFake" />
<!-- fake input to display the path of the selected file : end -->
</div>
<input id="ClonedFromFoodID" name="ClonedFromFoodID" type="hidden" value="<%=Model.Food.ClonedFromFoodID %>" />
<input id="IsUserFood" name="IsUserFood" type="hidden" value="<%=Model.Food.IsUserFood %>" />
<input id="Img200x200" name="Img200x200" type="hidden" value="<%=Model.Food.Img200x200 %>" />
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
<script language="javascript" type="text/javascript">
$(document).ready(function() {
var isUserFood = '<%=Model.Food.IsUserFood %>';
var hasClones = '<%=Model.Food.HasClones %>';
var isClone = '<%=Model.Food.IsClone %>';
var canClone = window.location.toString().toLowerCase().indexOf("/edit") > -1;
var gettingCloned = window.location.toString().toLowerCase().indexOf("/clone") > -1
if (hasClones.toLowerCase() == 'true') {
$("#divCloningMessage").html("This food has already been cloned.");
canClone = 'false';
}
originalCreator = '<%=Model.Food.OriginalCreator%>';
clonedFromFoodID = '<%=Model.Food.ClonedFromFoodID%>';
$("#spanOriginalCreatorLabel").html("Original Creator:");
$("#spanOriginalCreator").html(originalCreator);
if (isClone.toLowerCase() == 'true') {
var originalCreator;
$("#spanClonedByLabel").html("Cloned By:");
$("#spanClonedBy").html("WFM Nutritionist");
$("#divCloningMessage").html("This food is cloned from food with id " + clonedFromFoodID + ".");
canClone = 'false';
}
if (canClone == true) {
utility.ui.makeYUIButton("btnCloneThisFood");
$("#btnCloneThisFood-button").click(function() {
var cloneFoodId = '<%=Model.Food.FoodID %>';
var clonedFoodUrl = '<%=Url.Content("~/") %>foods/clone/' + cloneFoodId;
window.location = clonedFoodUrl;
});
$("#divBtnCloneThisFood").show();
}
var clonedFromFoodID = $("#ClonedFromFoodID").val();
if (gettingCloned) {
$("#spanFoodID").html("0");
}
utility.ui.makeYUIButton("btnNewCompany");
checkForBasicFood();
$("#ddlFoodType").change(function() {
checkForBasicFood();
});
$("#btnNewCompany").click(function() {
var btnID, txtNameId, txtDescId, catId, catName, eleToUpdateId, uiUpdateType;
btnID = "btnNewCompany";
txtNameId = $("input[boundbutton='" + btnID + "']").attr('id');
txtDescId = $("textarea[boundbutton='" + btnID + "']").attr('id');
catId = $("input[boundbutton='" + btnID + "']").attr('catId');
eleToUpdateId = $("input[boundbutton='" + btnID + "']").attr('updateEle');
catName = $("input[boundbutton='" + btnID + "']").attr('catName');
uiUpdate = $("input[boundbutton='" + btnID + "']").attr('uiUpdateType');
if ($("#" + txtNameId).val() == "")
$("div[boundButton='" + btnID + "']").fadeIn().fadeOut(10000);
else {
var subCategory = {
categoryId: catId,
parentCategoryId: $("#ddlFoodType").val(),
categoryLevel: 2,
categoryName: $("#" + txtNameId).val(),
categoryDescription: $("#" + txtDescId).val(),
categoryIconPath: "",
sortOrder: 0
};
// Initializing food helper
foodHelper.init('<%= Url.Content("~/") %>');
foodHelper.addSubCategory(subCategory, {
updateElementId: eleToUpdateId,
updateDropdownID: "ddlCompany",
categoryName: catName,
messageDivId: catName + "Message",
catNameTxtBoxId: txtNameId,
catDescTxtBoxId: txtDescId,
uiUpdateType: uiUpdate
});
}
});
});
function checkForBasicFood() {
if ($("#ddlFoodType").val() == 1444 || $("#ddlFoodType").val() == -1) { // Bad: hard coding value
$("#rowCompany").hide();
$("#rowAddCompany").hide();
}
else {
var selectedFoodType = $("#ddlFoodType").val();
if (selectedFoodType == 688) {
$("#spanCompany").html("Restaurant Brand:");
$("#spanAddCompany").html("Add a New Restaurant Brand:");
$("#divAddCompanyError").html("Please enter name for Restaurant Brand.");
}
else if (selectedFoodType == 689) {
$("#spanCompany").html("Store Brand:");
$("#spanAddCompany").html("Add a New Store Brand:");
$("#divAddCompanyError").html("Please enter name for Store Brand.");
}
$("#rowCompany").show();
$("#rowAddCompany").show();
}
}
</script>

Personally, I think it is very odd to have properties of type SelectList and List<CheckBoxInfo> in your view model class. Most viewmodels should contain properties of very basic types, like string and int. The way you have, makes it very hard to debug & identify your problems but I would go and say that most likely the default model binder doesn't know how to bind values from HTML controls to your viewmodel props.
I would advise looking into building a custom modelbinder or rewriting the view model class. Or rewriting the app as a whole (but I guess that's not an option).
HTH

Certain property name don't match with actual names............need to modify

Related

.Net 6 - Passing a radio button selected table row to a controller

I really feel like this should be easy but I’m thinking it may have changed with .Net 6. I can pass values to my controller with the input “name=’name’” but for some reason I cannot get any values from my model into my controller. I am trying to POST my row values to the controller. I am using an enumerable. I’m not sure if I should be using a or not. Another thing is how should I be populating my table row from a loop of the model. I thought using #Html. Was for older .net and tag helpers are the new way but I couldn’t get any to work populating my rows.
<form method="post">
<div id="tblPullParts" class="container justify-content-center mt-3">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th >Order #</th>
<th >Item</th>
<th >Description</th>
<th >Quantity</th>
</tr>
</thead>
<tbody>
#foreach (var p in Model)
{
<tr>
<td><input type="radio" id="radio" name="radio"
value="#Html.DisplayFor(item => p.PartID)" /></td>
#*<td><input asp-for="Selected" type="radio" value="Selected" /></td>*#
<th scope="row">#Html.DisplayFor(item => p.PartID)</th>
<td>#Html.DisplayFor(item => p.Name)</td>
<td>#Html.DisplayFor(item => p.ItemLocation)</td>
<td>#Html.DisplayFor(item => p.PartGroup)</td>
<td>#Html.DisplayFor(item => p.Description)</td>
<td>
<input type="text" asp-for="#p.Name" id="txtNameN" />
</td>
</tr>
}
</tbody>
</table>
#*<input type="text" id="#Model[0].Name" />*#
<input type="text" id="txtName" name="txtName" value="" />
</div>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-success mt-3">Start Pick</button>
</div>
</form>
[HttpPost]
public async Task<IActionResult> Index( PartVM model, string radio, string txtName)
{
if (model?.PartID != 0)
{
return View("UpdatePickQuantity", model);
}
if (!String.IsNullOrWhiteSpace(txtName))
{
}
//Request.QueryString["radio"];
var lstParts = await _ordersService.GetAllParts();
return View(lstParts);
}
#Html.DisplayFor() can only display the value of model, If you want to submit the value, You need to use <input>,Here is a simple demo, I add hidden input in your form to submit the value:
#model List<PartVM>
#{
int i = 0;
}
<form method="post">
<div id="tblPullParts" class="container justify-content-center mt-3">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th >Order #</th>
<th >Item</th>
<th >Description</th>
<th >Quantity</th>
</tr>
</thead>
<tbody>
#foreach (var p in Model)
{
<tr>
<td><input type="radio" id="radio" name="radio"
value="#Html.DisplayFor(item => p.PartID)" /></td>
#*<td><input asp-for="Selected" type="radio" value="Selected" /></td>*#
<th scope="row">
#Html.DisplayFor(item => p.PartID)
<input type="hidden" asp-for="#p.PartID" name="[#i].PartID">
</th>
<td>
#Html.DisplayFor(item => p.Name)
</td>
<td>
#Html.DisplayFor(item => p.ItemLocation)
<input type="hidden" asp-for="#p.ItemLocation" name="[#i].ItemLocation">
</td>
<td>
#Html.DisplayFor(item => p.PartGroup)
<input type="hidden" asp-for="#p.PartGroup" name="[#i].PartGroup">
</td>
<td>
#Html.DisplayFor(item => p.Description)
<input type="hidden" asp-for="#p.Description" name="[#i].Description">
</td>
<td>
<input type="text" asp-for="#p.Name" name="[#i].Name" id="txtNameN" />
</td>
</tr>
i++;
}
</tbody>
</table>
#*<input type="text" id="#Model[0].Name" />*#
<input type="text" id="txtName" name="txtName" value="" />
</div>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-success mt-3">Start Pick</button>
</div>
</form>
Controller
[HttpPost]
public async Task<IActionResult> Index( List<PartVM> model, string radio, string txtName)
{
//.....
}
Demo:
Your second question can refer to this github issue.
Edit============================
If you want just want to pass the row where radio is selected, you need to js to achieve this. refer to this:
Create a ViewModel
public class PartvmViewModel
{
public int PartID { get; set; }
public string Name { get; set; }
public string ItemLocation { get; set; }
public string PartGroup { get; set; }
public string Description { get; set; }
public string? txtName { get; set; }
}
controller
public IActionResult Display()
{
List<PartvmViewModel> viewmodel = new List<PartvmViewModel>();
//pass data from PartVM to PartvmViewModel
foreach (var item in PartVms)
{
viewmodel.Add(new PartvmViewModel()
{
PartID = item.PartID,
Description = item.Description,
ItemLocation = item.ItemLocation,
Name = item.Name,
PartGroup = item.PartGroup
});
}
return View(viewmodel);
}
[HttpPost]
public IActionResult Display([FromBody]PartvmViewModel model)
{
//because the value of radio is equal to PartID,SO i don't write it as parameter here
//.........
}
View
#model List<PartvmViewModel>
#{
int i = 0;
}
<form method="post">
<div id="tblPullParts" class="container justify-content-center mt-3">
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th >Order #</th>
<th >Item</th>
<th >Description</th>
<th >Quantity</th>
</tr>
</thead>
<tbody>
#foreach (var p in Model)
{
<tr>
<td><input type="radio" name="radio" onclick="Method(this)"
value="#Html.DisplayFor(item => p.PartID)" /></td>
#*<td><input asp-for="Selected" type="radio" value="Selected" /></td>*#
<th scope="row">
#Html.DisplayFor(item => p.PartID)
<input type="hidden" asp-for="#p.PartID" name="[#i].PartID" id="PartID">
</th>
<td>
#Html.DisplayFor(item => p.Name)
</td>
<td>
#Html.DisplayFor(item => p.ItemLocation)
<input type="hidden" asp-for="#p.ItemLocation" name="[#i].ItemLocation" id="ItemLocation">
</td>
<td>
#Html.DisplayFor(item => p.PartGroup)
<input type="hidden" asp-for="#p.PartGroup" name="[#i].PartGroup" id="PartGroup">
</td>
<td>
#Html.DisplayFor(item => p.Description)
<input type="hidden" asp-for="#p.Description" name="[#i].Description" id="Description">
</td>
<td>
<input type="text" asp-for="#p.Name" name="[#i].Name" id="txtNameN" />
</td>
</tr>
i++;
}
</tbody>
</table>
#*<input type="text" id="#Model[0].Name" />*#
<input type="text" id="txtName" name="txtName" value="" />
</div>
<div class="text-center">
<button class="btn btn-lg btn-success mt-3" onclick="Submit()">Start Pick</button>
</div>
</form>
#section Scripts
{
<script>
var Data;
function Method(obj){
this.Data = {
"PartID":$(obj).val(),
"ItemLocation" : $(obj).parent().parent().find('td:eq(2)').find(':input').val(),
"PartGroup" : $(obj).parent().parent().find('td:eq(3)').find(':input').val(),
"Description" : $(obj).parent().parent().find('td:eq(4)').find(':input').val(),
"Name" : $(obj).parent().parent().find('td:eq(4)').find(':input').val(),
}
}
function Submit(){
Data.txtName = $("#txtName").val();
$.ajax({
url : '/Home/Display',
type : 'post',
data : JSON.stringify(Data),
contentType : 'application/json'
});
}
</script>
}
My opinion==========================
Actually, In my opinion, Pass the list of data is ok. Because i notice that you pass the value of radio into the controller, You can just use:
[HttpPost]
public async Task<IActionResult> Index( List<PartVM> model, string radio, string txtName)
{
var item = model.Where(i => i.PartID == int.Parse(radio)).FirstOrDefault();
//.....
}
to get the selected row, It is more easier than using js;
Instead of doing this
<th scope="row">
#Html.DisplayFor(item => p.PartID)
<input type="hidden" asp-for="#p.PartID" name="[#i].PartID" id="PartID">
</th>
I would do something like
<th scope="row">
<p>#p.PartID</p>
<input type="hidden" asp-for="#p.PartID" name="[#i].PartID" id="PartID">
</th>
However, I could be wrong because you are using razor syntax and I am not use to that yet ;)

I have a problem when I try to render a partial view in may main view

I have the following partial view:
#model IDECOHealthInsurance.Models.Pharmacy
#using (Ajax.BeginForm("pharmacyDetials", "Pharmacy", new AjaxOptions { HttpMethod = "Get", UpdateTargetId = "pDetail", InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace, LoadingElementId = "Loading", OnBegin = "" }))
{
<h4>تفاصيل الصيدلية</h4>
<div id="pDetail" class="MainGridContainer pb-5">
#if (Model.dtItemsDetails != null)
{
<table dir="rtl" id="Paitents" class="MainGrid">
<thead>
<tr style="text-size-adjust:auto">
<th>
رقم الموظف
</th>
<th>
التاريخ
</th>
<th>
الوقت
</th>
<th>
المستفيدون
</th>
<th>
ملاحظات
</th>
<th>
الباركورد
</th>
<th>
أسم العينة
</th>
<th>
الكمية
</th>
<th>
السعر
</th>
</tr>
</thead>
<tbody>
#foreach (System.Data.DataRow row in Model.dtItemsDetails.Rows)
{
<tr style="width:100%">
<td>
#row["EMPLOYEE_NUMBER"]
</td>
<td>
#row["ENTRY_DATE"]
</td>
<td>
#row["ENTRY_TIME"]
</td>
<td>
#row["BENEFICIARIES"]
</td>
<td>
#row["NOTE"]
</td>
<td>
#row["ITEM_CODE"]
</td>
<td>
#row["ITEM_NAME"]
</td>
<td>
#row["QTY"]
</td>
<td>
#row["PRICE"]
</td>
</tr>
}
</tbody>
</table>
}
</div>
}
And the follwing controller:
[HttpGet]
public ActionResult pharmacyDetials(Pharmacy model)
{
var masterID = Convert.ToInt32(Session["login"]);
if (masterID == 0)
{
return RedirectToAction("Login");
}
else
{
Models.Pharmacy objPharamcyMode = new Pharmacy();
IDECOServiceReference.IdecoAPIServiceClient idecoAPI = new IDECOServiceReference.IdecoAPIServiceClient();
DataTable dataTable = idecoAPI.GETPHARMACYEMPLOYEEMASTER("", 1);
model.dtItemsDetails = dataTable;
return PartialView("_PharmacyDetails", model);
}
}
And the following main view:
#model IDECOHealthInsurance.Models.Pharmacy
#{
ViewBag.Title = "PharmacyApplication";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<table style="height:680px; width:1280px; border:hidden">
<tr>
<td>
<div id="pDetail">
#Html.Partial("_PharmacyDetails", Model)
</div>
</td>
<td>
#using (Ajax.BeginForm("PharmacyApplication", "Pharmacy", new AjaxOptions { HttpMethod = "Post", UpdateTargetId = "updatePnl", InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace, LoadingElementId = "Loading", OnBegin = "" }))
{
<div class="form-horizontal">
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" id="panel" value="أضافة" class="btn btn-default" />
</div>
<input class="btn btn-default" type="button" value="خروج" onclick="#("window.location.href='" + #Url.Action("LogOut", "Pharmacy") + "'");" />
</div>
</div>
}
</td>
</tr>
</table>
<div id="updatePnl">
#Html.Partial("_PartialPharmacyDetails", Model)
</div>
<br />
<br />
<br />
<div id="pnlItemsDetails">
#Html.Partial("_PartialItemsDetails", Model)
</div>
When I try to render _PharmacyDetails in my main view it won't return any records. What is the problem? and how I can fix it? Please provide me with an explanation of how this problem occurs. What did I do wrong?
Instead of using Partial method to render the partial view I used Action method:
<tr>
<td>
<div id="pDetail" style="background-color:aliceblue" method="Get">
#Html.Action("pharmacyDetials", Model)
</div>
</td>
<td>

Controller can't receive model data [duplicate]

This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 6 years ago.
Hi I want to grab all user modify data.
My question is why controller can't receive the model data from View in my project.
Please explain why this error was caused and how to solve it.
Models:
public class ShoppingCart
{
public List<ShoppingCartItemModel> items = new List<ShoppingCartItemModel>();
public IEnumerable<ShoppingCartItemModel> Items
{
get { return items; }
}
}
public class ShoppingCartItemModel
{
public Product Product
{
get;
set;
}
public int Quantity { get; set; }
}
Controller
[HttpPost]
public RedirectToRouteResult EditFromCart(ShoppingCart MyModel)
{
ShoppingCart cart = GetCart();
foreach (var CartItem in cart.items)
{
foreach (var ReceiveModelItem in MyModel.items)
{
if (CartItem.Product.ProductID == ReceiveModelItem.Product.ProductID)
{
CartItem.Quantity = ReceiveModelItem.Quantity;
}
}
}
return RedirectToAction("Index", "ShoppingCart");
}
View
#model ShoppingCart
#{
ViewBag.Title = "購物車內容";
}
<h2>Index</h2>
<table class="table">
<thead>
<tr>
<th>
Quantity
</th>
<th>
Item
</th>
<th class="text-right">
Price
</th>
<th class="text-right">
Subtotal
</th>
</tr>
</thead>
<tbody>
#using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Post))
{
foreach (var item in Model.items)
{
<tr>
<td class="text-center">
#item.Product.ProductName
</td>
<td class="text-center">
#item.Product.Price.ToString("c")
</td>
<td class="text-center">
#( (item.Quantity * item.Product.Price).ToString("c"))
</td>
<td class="text-left">
#Html.EditorFor(model => item.Quantity, null, "UserInputQuantity")
#Html.Hidden("ProductId", item.Product.ProductID)
</td>
</tr>
}
<tr>
<td colspan="3">
<input class="btn btn-warning" type="submit" value="Edit">
</td>
</tr>
}
</tbody>
</table>
You must explicitly create a hidden input for each property in your complex object that you want to be bound. IEnumerables and binding don't play very nicely directly out of the box - it looks like MVC has better base support for IList<> and arrays, but you'll still have to enumerate the collection and create hidden inputs for each item. Have a look at this link. So, ideally your view should be:
#model ShoppingCart
#{
ViewBag.Title = "購物車內容";
}
<h2>Index</h2>
<table class="table">
<thead>
<tr>
<th>
Quantity
</th>
<th>
Item
</th>
<th class="text-right">
Price
</th>
<th class="text-right">
Subtotal
</th>
</tr>
</thead>
<tbody>
#using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Post))
{
for (int i = 0; i < Model.items.Count(); ++i)
{
<tr>
<td class="text-center">
#Model.items[i].Product.ProductName
</td>
<td class="text-center">
#Model.items[i].Product.Price.ToString("c")
</td>
<td class="text-center">
#( (Model.items[i].Quantity * Model.items[i].Product.Price).ToString("c"))
</td>
<td class="text-left">
#Html.EditorFor(model => Model.items[i].Quantity)
#Html.HiddenFor(model => Model.items[i].Product.ProductID)
#Html.HiddenFor(model => Model.items[i].Product.ProductName)
#Html.HiddenFor(model => Model.items[i].Product.Price)
</td>
</tr>
}
<tr>
<td colspan="3">
<input class="btn btn-warning" type="submit" value="Edit">
</td>
</tr>
}
</tbody>
</table>
Names are not correctly set for your text and hidden inputs:
#Html.EditorFor(model => item.Quantity, null, "UserInputQuantity")
#Html.Hidden("ProductId", item.Product.ProductID)
If you inspect elements you can see names are UserInputQuantity and ProductId, but they should be
items[i].Quantity and items[i].Product.ProductID respectively.
You can take a look at this link:
MVC Model binding of complex objects

How to preserve model values during postback?

I have a model:
public class EmployeeDetails
{
public int staffcode { get; set; }
public string name { get; set; }
public string designation { get; set; }
public string department { get; set; }
}
On click of Search button, employee details are fetched from the database and model properties are initialized. These values are also shown on the View.
dtEmpDetails = lib.RunSP("GetEmpDetails", lstEmpDetails);
leaveBalanceViewModel.EmployeeDetail.staffcode = Convert.ToInt32(staffCode);
leaveBalanceViewModel.EmployeeDetail.name = dtEmpDetails.Rows[0][0].ToString();
leaveBalanceViewModel.EmployeeDetail.designation = dtEmpDetails.Rows[0][1].ToString();
There is another button Save. When I click Save, the Textbox values from the View get lost because again a Submit is happening.
How can I store the model property values and keep it available during postbacks?
** Edited **
View Code is as below:
<div>
#using (Html.BeginForm("Search", "AFLeaveBalance",FormMethod.Get))
{
<table style="border:none">
<tr>
<td style="border:none">Enter staff code</td>
<td style="border:none">#Html.TextBox("staffcode", "", new { width = "100" })</td>
<td style="border:none"><input type="submit" value="Get Details" /></td>
</tr>
</table>
}
<br /><hr />
<table id="tblEmpDetails">
<tr>
<td style="background-color:#d2eef7; width:200px;text-align:left">Employee Name</td>
<td>#Html.TextBoxFor(m => m.EmployeeDetail.name, new { #readonly = "ReadOnly", #class = "ReadOnly", style = "width:300px" })</td>
#Html.HiddenFor(m => m.EmployeeDetail.name)
</tr>
<tr>
<td style="background-color:#d2eef7;width:200px;text-align:left">Designation</td>
<td >
#Html.TextBoxFor(m => m.EmployeeDetail.designation, new { #readonly = "ReadOnly", #class = "ReadOnly", style="width:300px" })
</td>
</tr>
<tr>
<td style="background-color:#d2eef7;width:200px;text-align:left">Directorate</td>
<td>#Html.TextBoxFor(m => m.EmployeeDetail.directorate, new { #readonly = "ReadOnly", #class = "ReadOnly", style = "width:300px" })</td>
</tr>
</table>
<br /><hr />
#using (Html.BeginForm("Save", "AFLeaveBalance", FormMethod.Post))
{
<table id="tblCurrentYear">
<tr style="background-color:#d2eef7;color:Black;font-weight:200">
<td colspan="4">
#Html.Label("Year: " + DateTime.Now.Year.ToString())
</td>
</tr>
<tr style="background-color:#d2eef7;color:Black;">
<td>Leave Type</td>
<td>Leave Taken</td>
<td>Leave Balance</td>
<td>Leave Total</td>
</tr>
#*#for (int i = 0; i < Model.LeaveDetailsList.Count; i++)*#
#*{*#
<tr>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveType, new { #class = "ReadOnly", #readonly = "readonly", style = "width:80px; text-align:center" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveTaken, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveBalance, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveTotal, new { width = "100" })</td>
</tr>
<tr>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveType, new { #class = "ReadOnly", #readonly = "readonly", style = "width:80px; text-align:center" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveTaken, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveBalance, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveTotal, new { width = "100" })</td>
</tr>
#*}*#
</table>
<br />
<table style="border:none">
<tr>
<td style="width:600px;text-align:left;border:none">
<input id="btnSave" type="submit" value="Save" style="width:100px" />
</td>
</tr>
</table>
}
</div>
The simplest way is to store all you need in session on the server and then to populate all you need from that session after submit.

No model binding with editor template

I have following view:
#model StockItemDetailModel
#using (Html.BeginForm("EditDetails", "StockItem"))
{
<div class="ItemDetails">
<table class="datagrid">
<tr>
<th colspan="3">#Model.StockItemPropertiesCaption</th>
</tr>
<tr>
<td class="label">#Model.StoreLabel</td>
<td class="value">#Html.DisplayFor(item => item.Store)</td>
<td></td>
</tr>
<tr>
<td class="label">#Model.BuildingLabel</td>
<td class="value">#Html.DevExpress().TextBoxFor(model => model.Building).GetHtml()</td>
<td class="validationError">#Html.ValidationMessageFor(model => model.Building)</td>
</tr>
...
<tr>
<td colspan="3">#Html.EditorFor(model => model.AmountModel, "Amounts")</td>
> </tr>
<tr>
<td colspan="3" class="validationError">#Html.ValidationMessageFor(model => model.AmountModel)</td>
</tr>
<tr />
</table>
</div>
<br />
<input type="submit" class="button" value="#Model.SaveButtonLabel" />
}
The partial View "Amounts" is as follows:
#model AmountModel
<table>
<tr>
<td class="label">#Model.AmountLabel</td>
<td class="value">
#Html.DevExpress().SpinEditFor(model => model.DenormalizedNetAmount,
settings =>
{
settings.Name = "DenormalizedNetAmount";
settings.Width = 153;
settings.Properties.DisplayFormatString = #"0.0,0";
settings.Number = 0;
}).GetHtml()
</td>
<td class="value">
#Html.DevExpress().ComboBoxFor(model => model.NetAmountUnit,
settings =>
{
settings.Name = "NetAmountUnit";
settings.Width = 60;
}).BindList(args => this.Model.AllUnits, args => this.Model.AllUnits).GetHtml()
</td>
</tr>
...
</table>
This is the AmountModel:
public class AmountModel
{
public decimal DenormalizedNetAmount { get; set; }
public string NetAmountUnit { get; set; }
...
public string AmountLabel
{
get { return i18n.StockItemDetailModel_AmountLabel; }
}
...
}
But the values of the input fields are not in the model in the Controller created by the model binder.
Why does the model binder not recognize the values in the editor template?
When I passed the FormCollection the values where correctly passed under the names "AmountModel.~"
public ActionResult EditDetails(FormCollection collection)
{
var netamount = collection["AmountModel.DenormalizedNetAmount"]; //correct value!
...
}
Do NOT specify the Name property when using the strong-typed (***For) helpers.
See the MVC Data Editors - Model Binding and Editing learning resource on the DevExpress forum.

Resources