Reputation: 374
I've been struggeling with this one for quite a while. Everything goes as planned until I try to return the values filled in from the View back to the Controller (See below):
Using Fiddler, as soon as I submit the data it shows valid html (Please see below:)
To my understanding, this should bind to the model. I am posting back to the Finance ActionResult, but this is what I am getting:
NULL is returned in ActionResult Finance
I just don't understand this. I am passing a List into the View:
@model List<FinanceMVC.Models.FinanceViewModel>
And my ActionResult is expecting the following:
List<FinanceViewModel> finance
I have a feeling I have a problem in my model somewhere, and I've tried my best to find it, but I just can't see it. Has anyone experienced this before? Please can someone lend a hand.
Please see my code below:
I have the following Model:
namespace FinanceMVC.Models
{
//public class Finance
//{
//}
public class FinanceViewModel
{
/*ID*/
//[Required]
//[Display(Name = "ID")]
//public int ID { get; set; }
/*BINL_BIND_ID*/
[Required]
[Display(Name = "Invoice Type")]
public IEnumerable<SelectListItem> InvoiceType { get; set; }
/*BINL_Inv_Num_Pointer*/
[RegularExpression(@"^[0-9]*$",
ErrorMessage = "Email is not valid")]
[Required]
[Display(Name = "Invoice Number")]
public string InvoiceNumber { get; set; }
/*BINL_Inv_Num_Period*/
[Required]
[Display(Name = "Invoice Number Period")]
public IEnumerable<SelectListItem> InvoiceNumberPeriod { get; set; }
//public List<C_Period> InvoiceNumberPeriod { get; set; }
/*BINL_Created*/
[Display(Name = "Invoice Created Date")]
[Required]
[DataType(DataType.DateTime)]
public DateTime InvoiceDateCreated { get; set; }
///*BINL_SystemInserted*/
//[Required]
//[Display(Name = "Invoice System Inserted")]
//public bool InvoiceSystemInserted { get; set; }
}
public class C_InvoiceType
{
public int ID { get; set; }
public string Description { get; set; }
}
public class C_Period
{
public int Period { get; set; }
}
public class ReturnInfo
{
string InvoiceType { get; set; }
string InvoiceNumber { get; set; }
string InvoiceNumberPeriod { get; set; }
string InvoiceDateCreated { get; set; }
}
}
View:
@model List<FinanceMVC.Models.FinanceViewModel>
@{
ViewBag.Title = "Index";
}
@using (Html.BeginForm("Finance", "Finance", FormMethod.Post, new { @class = "form-horizontal" }))
{
<div class="col-md-1 fade in" style="margin-left: 5%; width: 100%; font-size: 11px; height: auto;">
<div id="div_Finance_Container" style="width: 100%; height: 80%; overflow: auto; text-align: left;" runat="server" class="scroll-pane">
<div style="height: 500px; overflow: auto;">
<table id="dataTable" border="0">
@for(int i = 0; i <Model.Count; i++)
{
<tr>
@Html.Label("The next recommended Invoice Number is: ", "The next recommended Invoice Number is: " + Model[i].InvoiceNumber, new { style="font-weight:bold;" })
</tr>
<br />
<tr class="tr_clone">
<td>
<div class="col-md-1" style="width: 20%;">
@Html.DropDownList("InvoiceType[" + @i + "].InvoiceType", Model[i].InvoiceType)
</div>
</td>
<td>
@Html.TextBox("InvoiceNumber[" + @i + "].InvoiceNumber", Model[i].InvoiceNumber)
</td>
<td>
@Html.DropDownList("InvoiceNumberPeriod[" + @i + "].InvoiceNumberPeriod", Model[i].InvoiceNumberPeriod, new { @class = "InvoiceNumberPeriod", string.Empty })
</td>
<td>
@Html.TextBox("InvoiceDateCreated[" + @i + "].InvoiceDateCreated", Model[i].InvoiceDateCreated, new { @class = "InvoiceDateCreated", @type = "date" })
</td>
<td>
<input type="button" name="add" value="Add another record" class="tr_clone_add">
</td>
</tr>
}
</table>
<input type="submit" value="Save Bulk Data" />
</div>
</div>
</div>
}
and Controller:
public class FinanceController : Controller
{
public ActionResult Finance()
{
List<C_Period> c_Per = new List<C_Period>();
// This is only for show by default one row for insert data to the database
List<FinanceViewModel> FinanceViewList = new List<FinanceViewModel>
{
new FinanceViewModel
{
/*ID = 0 ,*/ InvoiceType = ListInvoiceTypesForFinances() /*ReturnInvoiceType()*/, InvoiceNumber = ReturnInvoiceNumber(), InvoiceNumberPeriod = ListInvoiceNumPeriodForFinances() /*c_Per*/, InvoiceDateCreated = DateTime.Now, /*InvoiceSystemInserted = false*/
},
new FinanceViewModel
{
/*ID = 0 ,*/ InvoiceType = ListInvoiceTypesForFinances() /*ReturnInvoiceType()*/, InvoiceNumber = ReturnInvoiceNumber(), InvoiceNumberPeriod = ListInvoiceNumPeriodForFinances() /*c_Per*/, InvoiceDateCreated = DateTime.Now, /*InvoiceSystemInserted = false*/
},
new FinanceViewModel
{
/*ID = 0 ,*/ InvoiceType = ListInvoiceTypesForFinances() /*ReturnInvoiceType()*/, InvoiceNumber = ReturnInvoiceNumber(), InvoiceNumberPeriod = ListInvoiceNumPeriodForFinances() /*c_Per*/, InvoiceDateCreated = DateTime.Now, /*InvoiceSystemInserted = false*/
}
};
return View(FinanceViewList);
}
//
// GET: /Finance/
/*Matches file name of Finance.cshtml*/
//[HttpPost]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Finance(List<FinanceViewModel> finance)
{
if (ModelState.IsValid)
{
}
return null;
}
//
// GET: /Finance/Welcome/
//public string Index()
//{
// return "This is the Welcome action method...";
//}
public static string ReturnInvoiceNumber()
{
string sQ = ""
+ " Select Max(BINL_Inv_Num_Pointer) AS [Last Invoice Number] \n"
+ " From Biller_InvoiceNum_List with(nolock) \n"
;
using (SqlConnection sCon = new SqlConnection(Application_Info.sMOB_Master_Conn()))
{
if (sCon.State != ConnectionState.Open)
{
sCon.Open();
}
using (SqlCommand sCmd = new SqlCommand(sQ, sCon))
{
using (SqlDataReader sRdr = sCmd.ExecuteReader())
{
string LastInvoiceRecordNumber = "";
while (sRdr.Read())
{
LastInvoiceRecordNumber = (string)sRdr["Last Invoice Number"];
}
int LastInvoiceLength = LastInvoiceRecordNumber.Length;
int number = int.Parse(LastInvoiceRecordNumber);
/*Increment to get recommended next Invoice Number*/
number = (number + 1);
string IntStr = number.ToString();
string NextInvoiceRecordNumber = IntStr.PadLeft(LastInvoiceLength, '0');
return NextInvoiceRecordNumber;
}
}
}
}
public static IEnumerable<C_InvoiceType> ReturnIType()
{
var srtQry = "\n"
+ " Select ID, BIND_Description \n"
+ " From Biller_InvoiceNum_DefSet with(nolock) \n"
;
using (var conn = new SqlConnection(Application_Info.sMOB_Master_Conn()))
using (var objCommand = new SqlCommand(srtQry, conn) { CommandType = CommandType.Text })
using (var dt = new DataTable())
using (var adp = new SqlDataAdapter(objCommand))
{
conn.Open();
adp.Fill(dt);
return dt.AsEnumerable().Select(o => new C_InvoiceType
{
ID = o.Field<int>("ID"),
Description = o.Field<string>("BIND_Description"),
}).ToList();
}
}
public static IEnumerable<SelectListItem> ListInvoiceTypesForFinances()
{
var listIVTypes = ReturnIType();
return listIVTypes
.Select(o => new SelectListItem
{
Text = o.Description,
Value = o.ID.ToString()
})
.ToList();
}
public static IEnumerable<C_Period> ReturnINumPeriod()
{
var srtQry = "\n"
+ " Select BINL_Inv_Num_Period \n"
+ " From Biller_InvoiceNum_List with(nolock) \n"
+ " Where ID = 99999 \n"
;
using (var conn = new SqlConnection(Application_Info.sMOB_Master_Conn()))
using (var objCommand = new SqlCommand(srtQry, conn) { CommandType = CommandType.Text })
using (var dt = new DataTable())
using (var adp = new SqlDataAdapter(objCommand))
{
conn.Open();
adp.Fill(dt);
return dt.AsEnumerable().Select(o => new C_Period
{
Period = o.Field<int>("BINL_Inv_Num_Period"),
}).ToList();
}
}
public static IEnumerable<SelectListItem> ListInvoiceNumPeriodForFinances()
{
var listIVTypes = ReturnINumPeriod();
return listIVTypes
.Select(o => new SelectListItem
{
Text = o.Period.ToString(),
Value = o.Period.ToString()
})
.ToList();
}
}
UPDATE:
So, changed View @Html helpers like below:
@for(int i = 0; i <Model.Count; i++)
{
<tr>
@Html.Label("The next recommended Invoice Number is: ", "The next recommended Invoice Number is: " + Model[i].InvoiceNumber, new { style="font-weight:bold;" })
</tr>
<br />
<tr class="tr_clone">
<td>
<div class="col-md-1" style="width: 20%;">
@*@Html.DropDownList("InvoiceType[" + @i + "].InvoiceType", Model[i].InvoiceType)*@
@Html.DropDownListFor(x => Model[i].InvoiceType, Model[i].InvoiceType)
</div>
</td>
<td>
@*@Html.TextBox("InvoiceNumber[" + @i + "].InvoiceNumber", Model[i].InvoiceNumber)*@
@Html.TextAreaFor(x => Model[i].InvoiceNumber)
</td>
<td>
@*@Html.DropDownList("InvoiceNumberPeriod[" + @i + "].InvoiceNumberPeriod", Model[i].InvoiceNumberPeriod, new { @class = "InvoiceNumberPeriod", string.Empty })*@
@Html.DropDownListFor(x => Model[i].InvoiceNumberPeriod, Model[i].InvoiceNumberPeriod, new { @class = "InvoiceNumberPeriod", string.Empty })
</td>
<td>
@*@Html.TextBox("InvoiceDateCreated[" + @i + "].InvoiceDateCreated", Model[i].InvoiceDateCreated, new { @class = "InvoiceDateCreated", @type = "date" })*@
@Html.TextBoxFor(x => Model[i].InvoiceDateCreated, new { @class = "InvoiceDateCreated", @type = "date" })
</td>
<td>
<input type="button" name="add" value="Add another record" class="tr_clone_add">
</td>
</tr>
}
Still having problems with drop down lists displaying:
Upvotes: 1
Views: 4253
Reputation: 151720
If you use them, your prefixes need to match your action parameter's name:
@Html.TextBox("finance[" + i + "].InvoiceNumber", Model[i].InvoiceNumber)
@Html.DropDownList("finance[" + i + "].InvoiceNumberPeriod", Model[i].InvoiceNumberPeriod, new { @class = "InvoiceNumberPeriod", string.Empty })
@Html.TextBox("finance[" + i + "].InvoiceDateCreated", Model[i].InvoiceDateCreated, new { @class = "InvoiceDateCreated", @type = "date" })
They are not required though when you have only one parameter, in which case you can use:
@Html.TextBox("[" + i + "].Property", ...)
You also can, and actually should, use the For
methods:
@Html.TextBoxFor(m => m[i].InvoiceNumber, ...)
@Html.DropDownListFor(m => m[i].InvoiceNumberPeriod, ...)
@Html.TextBoxFor(m => m[i].InvoiceDateCreated, ...)
Upvotes: 2
Reputation: 62498
You have to write it like this:
@Html.DropDownList("[" + @i + "].InvoiceType", Model[i].InvoiceType)
@Html.TextBox("[" + @i + "].InvoiceNumber", Model[i].InvoiceNumber)
.................................
.................................
Because you don't have InvoiceType
collection property in your Model which has another property InvoiceType
when you write InvoiceType[0].InvoiceType
you are saying in my Model i have collection with name InvoiceType
which has a Property name InvoiceType
which is not the case
Better approach is to use For Helpers which will automatically bind control value with Model:
@Html.DropDownListFor(x=> Model[i].InvoiceType)
@Html.TextBoxFor (x=> Model[i].InvoiceNumber)
.................................
.................................
You can also refere this related SO post
Upvotes: 1
Reputation:
OMG. Use the strongly typed helpers. None of your control names match your property names
@Html.TextBoxFor(m => m[i].InvoiceNumber)
Upvotes: 1