Model
public class ImportFiles
{
public string FileName;
public bool FileSelected { get; set; }
}
Controller
(Trying to get files from a particular folder) File names are coming , both contain the word "employee" Then I am searching for a string , in the file name and taking some actions.
[HttpGet]
public ActionResult ImportFiles()
{
string folderpath = #"C:\Users\uvaish\Documents\Visual Studio 2010\Projects\MVCDemo\MVCDemo\Models";
string filename = "*";
string[] fileList = System.IO.Directory.GetFiles(folderpath, filename);//getting the file names from the folder as an array
List<ImportFiles> inputFiles = new List<ImportFiles>(fileList.Length);//making a list of same number of elements as the number of files
foreach (string str in fileList)
{
ImportFiles inputFile = new ImportFiles();
inputFile.FileName = Path.GetFileName(str);
inputFile.FileSelected = false;
inputFiles.Add(inputFile);
}
return View(inputFiles);
}
[HttpPost]
public string ImportFiles(List<ImportFiles> import)
{
foreach (ImportFiles importFile in import)
{
if (importFile.FileSelected == true)
{
if (importFile.FileName.Contains("ployee"))//Getting a null point reference here
{
return ("file found");
}
else
{
return ("no file found");
}
}
else
{
return ("no file selected");
}
}
return ("done");
}
View
#model IList<ProjectName.Model.ImportFiles>
#using AetnaCoventryMigration.Model;
#using (Html.BeginForm("ImportFiles", "Admin", FormMethod.Post))
{
<div class="panel panel-default">
<table width="550px" class="mGrid table">
<tr>
<th>
Select
</th>
<th>
File Name
</th>
</tr>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.EditorFor(x => x[i].FileSelected)
</td>
<td>
#Model[i].FileName
</td>
</tr>
}
</table>
In this program , I am trying to access the checkboxes as well as the file names for each object passed in the view. I am able to access the checkbox and know whether it is true or false ( checked or unchecked ) but I'm not able to access the file names.
Change
<td>
#Model[i].FileName
</td>
To :
#Html.DisplayFor(x => x[i].FileName)
or add
#Html.HiddenFor(x => x[i].FileName)
it is necessary to generate a field for the correct data binding
Related
I want to download the file that I uploaded in the database. The file stored in the byte array. I have created the getDataStudent function and it is working well.
My controller is below.
public class Student: Controller
{
private StudentViewModel getDataStudent(StudentViewModel model)
{
var students = db.students.ToList();
var documents = documentRepo.GetList_Documents();
var queryJoin1 =
from student in students
from document in documents.Where(w => student .UniqueNumber == w.UniqueNumber).DefaultIfEmpty()
select new StudentDto
{
ID = student.ID,
Name = student.Name,
File = document?.DetailFile ?? null, //file to download
};
IEnumerable <StudentDto> studentss= null;
studentss = queryJoin1;
return studentss;
}
public ActionResult Index(StudentViewModel model)
{
studentViewModel = getDataStudent(model);
return View(studentViewModel );
}
[HttpPost]
public FileResult DownloadFile()
{
//code
}
}
and my view is below
#model Student.Data.ViewModels.StudentViewModel
#using (Html.BeginForm())
{
<table class="table">
<tr>
<th>Name</th>
<th>File</th>
</tr>
#foreach (Student.Data.ViewModels.StudentViewModel item in Model)
{
<tr>
<td>#Html.DisplayFor(modelitem => item.Name)</td>
<td> #Html.DisplayFor(modelitem => item.File)</td>
</tr>
}
</table>
}
File Result is still empty, I confused using FileResult.
can you guys tell me how to download files using FileResult on the controller, using the getDataStudent function that I created.
I have never made a file download function before. please help:)
You can implement like this:
public FileStreamResult DownloadFile()
{
// get your students here
var students = ...
string name = "yourname.txt";
FileInfo info = new FileInfo(name);
if (!info.Exists)
{
using (StreamWriter writer = info.CreateText())
{
foreach(var item in students){
writer.WriteLine("{0} {1}", item.ID, item.Name);
}
}
}
return File(info.OpenRead(), "text/plain");
}
I am new to MVC and now stuck in a serious problem. it is for me, very serious
I need to load a view with a list of meetings (which is loading fine) in html , I have added a checkbox to each row also. Now I need to save to the database ,only the checked values. But the controller is returning null when posting.. Really stuck and cant find a solution.
Pls see code below which I have done
Model
public class aMeet
{
public List<AcceptedRecords> amList { get; set; }
public static List<AcceptedRecords> GetamList()
{
DataSet ds = new DataSet();
List<AcceptedRecords> resultlist = new List<AcceptedRecords>();
using (cmd)
{
cmd.CommandText = #"SELECT Line_code,person_code,person_address from tbl where meeting_code =859489;
ds = cmd.ExecuteDataSet();
}
if (!Utils.IsDataSetEmpty(ds))
{
AcceptedRecords tpmApp;
foreach (DataRow row in ds.Tables[0].Rows)
{
tpmApp = new AcceptedRecords();
tpmApp = tpmApp.LoadRecords(row);
resultlist.Add(tpmApp);
}
}
return resultlist;
}
}
Model
public class AcceptedRecords
{
public int line_Code { get; set; }
public string person_Name { get; set; }
public string person_Address { get; set; }
public bool extra_checked { get; set; }
}
View
#model projct.Models.aRecs
#using (Html.BeginForm("AddRecord","Home"))
{
<table id="tbl" style ="width:100%" cellpadding="0" cellspacing="0" class="race-fields">
<thead>
<tr>
<th style="width:500px">line code</th>
<th style="width:100px">name</th>
<th style="width:500px">address</th>
<th style="width:500px">extra</th>
</tr>
</thead>
<tbody>
<tr>
#for (int i = 0; i < Model.amList.Count; i++)
{
<tr class="EvenRow">
<td>
#Html.DisplayFor(m => m.amList[i].line_Code) </td>
<td>#Html.DisplayFor(m => m.amList[i].person_name) </td>
<td>#Html.DisplayFor(m => m.amList[i].person_address) </td>
<td>
#Html.CheckBoxFor(m => m.amList[i].extra_checked) </td>
</tr>
}
</tr>
<tr>
<span>
<input type="submit" Value ="Save"/>
</span>
</tr>
</tbody>
</table>
}
Controller
[HttpPost]
public ActionResult AddRecord(List<aMeet> spm)
{
if (spm == null)
throw new ApplicationException("No Parameters passed to Create");
int? appID = 0;
return Json(appID);
}
}
--- It Is triggering to controller on Save but model [spm] is null.
How to get this corrected. Here I need to save to database the tr elements that are checked. Please request any help. I have tried a lot of things but the model is always null/
Many thanks
Assuming your aRecs class has a amList property which is a list of AcceptedRecords
public class aRecs
{
public List<AcceptedRecords> amList { set; get; }
}
Assuming line_code value is a unique (may be primary key) to get a record from your corresponding table, In your view, you need to keep the line_code property value of each item in amList in a hidden field so that when the form is submitted you will get this value and using that you can query the corresponding record and update it.
#model YourNamespaceHere.aRecs
#using (Html.BeginForm("AddRecord","Home"))
{
<table>
#for (int i = 0; i < Model.amList.Count; i++)
{
<tr class="EvenRow">
<td>
#Html.DisplayFor(m => m.amList[i].line_Code)
</td>
<td>#Html.DisplayFor(m => m.amList[i].person_Name) </td>
<td>
#Html.CheckBoxFor(m=>m.amList[i].extra_checked)
#Html.HiddenFor(m => m.amList[i].line_Code)
</td>
</tr>
}
</table>
<input type="submit"/>
}
And in your HttpPost action, your parameter will be a single object of aRecs
[HttpPost]
public ActionResult AddRecord(aRecs model)
{
foreach (var item in model.amList)
{
var lineCode = item.line_Code;
var isChecked = item.extra_checked;
/// get the record using lineCode and update the record.
}
return RedirectToAction("Index");
}
I have a model, ApplicantBranchList, that is used as a property in a larger model as follows:
[Display(Name = "Where would you want to work?")]
public ApplicantBranchList PreferedBranches { get; set; }
ApplicantBranchList:
public class ApplicantBranchList : ViewModel
{
public ApplicantBranchItem HeaderItem { get; set; }
public ApplicantBranchList()
{
HeaderItem = new ApplicantBranchItem();
}
public void MapFromEntityList(IEnumerable<ApplicantBranch> applicantBranches)
{
var service = new BranchService(DbContext);
var selectedIds = applicantBranches.Select(b => b.BranchId);
Items = service.ReadBranches()
.Where(i => !i.IsDeleted)
.Select(p => new ApplicantBranchItem { BranchName = p.Name, WillWorkAt = selectedIds.Contains(p.Id) });
}
public IEnumerable<ApplicantBranchItem> Items { get; set; }
}
ApplicantBranchList has its own editor template, and an inner editor template for each item in ApplicantBranchList:
Views/Shared/EditorTemplates/ApplicantBranchList.cshtml:
#model Comair.RI.UI.Models.ApplicantBranchList
<table>
<tr>
<th style="display: none;"></th>
<th>
#Html.DisplayNameFor(model => model.HeaderItem.BranchName)
</th>
<th>
#Html.DisplayNameFor(model => model.HeaderItem.WillWorkAt)
</th>
</tr>
#foreach (var item in Model.Items)
{
#Html.EditorFor(m => item)
}
</table>
Views/Shared/EditorTemplates/ApplicantBranchItem.cshtml:
#model Comair.RI.UI.Models.ApplicantBranchItem
<tr>
<td style="display: none;">
#Html.HiddenFor(m => m.BranchId)
</td>
<td>
#Html.DisplayFor(m => m.BranchName)
</td>
<td>
#Html.EditorFor(m => m.WillWorkAt)
</td>
</tr>
This editor renders properly in the view, but in the post action:
public ActionResult Create(ApplicantProfileModel model)
{
if (ModelState.IsValid)
{
var branches = model.PreferedBranches;
PreferedBranches.Items is null.
What am I doing wrong?
The problem is that ASP.NET can't figure out how to bind to Model.Items property.
To to fix it replace:
public IEnumerable<ApplicantBranchItem> Items { get; set; }
with this:
public List<ApplicantBranchItem> Items { get; set; }
and instead of:
#foreach (var item in Model.Items)
{
#Html.EditorFor(m => item)
}
use this one:
#for (var i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(model => model.Items[i]) // binding works only with items which are accessed by indexer
}
With MVC and editor templates you don't need to manually move through a list and call #HTMLEditorFor.
Doing this:
#Html.EditorFor(model => model.Items)
is the same as:
#for (var i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(model => model.Items[i]) // binding works only with items which are accessed by indexer
}
MVC will handle the iteration through your items and generate your editor template once per item. As is noted in the comments your template must be named the same as your model. Also, your model definition should be a singular representation of your model, not of type IEnumerable. Lastly, as noted in the comments, if you specify the template name parameter in your call to #Html.EditorFor() you will not have the benefit of the automatic iteration over your collection. You will need to manually iterate as is demonstrated above.
I have a view that has 2 date pickers, one of which is a start date and the other of which is end date. I am able to get the user to select the start and end dates, redirect to a view that will have a list of Time worked where the user could change the date, enter time, and once they are done they should be able to click the save button and it should create a new instance of each time worked to the database. I got the view displaying with no problem, but when the form posts my enumerable model is null, the form collection only has one accessible item, and I am not sure why. Please take a look at the view I am creating below to get an idea of what I am doing and let me know if you are able to help me in any way.
#model IEnumerable<TimeCollection.Models.TimeWorked>
#{
ViewBag.Title = "Create TimeWorked Range";
}
<h2>Create TimeWorked Range</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.WorkDate)
</th>
<th>
#Html.DisplayNameFor(model => model.HoursWorked)
</th>
</tr>
#foreach (var item in Model) {
<tr>
#Html.HiddenFor(modelItem => item.EmployeeId)
<td>
#Html.EditorFor(modelItem => item.WorkDate)
</td>
<td>
#Html.EditorFor(modelItem => item.HoursWorked)
</td>
<td>
#Html.HiddenFor(modelItem => item.BeenSubmitted)
</td>
</tr>
}
</table>
<p>
<input type="submit" value="Save" />
</p>
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TimeCollection.Models
{
public class TimeWorked
{
public int TimeWorkedId { get; set; }
public int EmployeeId { get; set; }
public DateTime WorkDate { get; set; }
public int HoursWorked { get; set; }
public bool BeenSubmitted { get; set; }
public static void CreateTimeWorked(TimeWorked timeWorkedToCreate)
{
string insertQuery = string.Format("insert into time_worked (employee_id, work_date, work_hours, been_submitted) values ('{0}', '{1}', '{2}', '{3}')", timeWorkedToCreate.EmployeeId, timeWorkedToCreate.WorkDate.ToString("yyyy/MM/dd"), timeWorkedToCreate.HoursWorked, (timeWorkedToCreate.BeenSubmitted == true ? "1" : "0"));
SpectrumData.Utility.ExecuteMySqlCommand(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, insertQuery);
}
public static TimeWorked ReadTimeWorked(int timeWorkedId)
{
string selectQuery = string.Format("select * from time_worked where time_worked_id = '{0}'", timeWorkedId);
return ConvertDataRowIntoTimeWorked(SpectrumData.Utility.FillDataSet(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, selectQuery).Tables[0].Rows[0]);
}
public static void UpdateTimeWorked(TimeWorked timeWorkedToUpdate)
{
string updateQuery = string.Format("update time_worked set work_date = '{0}', work_hours = '{1}', been_submitted = '{2}' where time_worked_id = '{2}'", timeWorkedToUpdate.WorkDate, timeWorkedToUpdate.HoursWorked, timeWorkedToUpdate.BeenSubmitted, timeWorkedToUpdate.TimeWorkedId);
SpectrumData.Utility.ExecuteMySqlCommand(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, updateQuery);
}
public static void DeleteTimeWorked(int timeWorkedId)
{
string deleteQuery = string.Format("delete from time_worked where time_worked_id = '{0}'", timeWorkedId);
SpectrumData.Utility.ExecuteMySqlCommand(SpectrumData.Properties.Resources.SpectrumTSDatabaseConnectionString, deleteQuery);
}
private static TimeWorked ConvertDataRowIntoTimeWorked(System.Data.DataRow timeWorkedDataRow)
{
TimeWorked timeWorked = new TimeWorked();
timeWorked.BeenSubmitted = (timeWorkedDataRow["been_submitted"].ToString() == "1" ? true : false);
timeWorked.EmployeeId = int.Parse(timeWorkedDataRow["employee_id"].ToString());
timeWorked.HoursWorked = int.Parse(timeWorkedDataRow["work_hours"].ToString());
timeWorked.TimeWorkedId = int.Parse(timeWorkedDataRow["time_worked_id"].ToString());
timeWorked.WorkDate = DateTime.Parse(timeWorkedDataRow["work_date"].ToString());
return timeWorked;
}
}
}
public ActionResult CreateTimeWorkedRange(DateTime startDate, DateTime endDate)
{
List<Models.TimeWorked> listOfTimeWorked = new List<Models.TimeWorked>();
DateTime beginning = startDate;
DateTime ending = endDate;
while (beginning <= ending)
{
Models.TimeWorked dayWorked = new Models.TimeWorked()
{
EmployeeId = (Session["InventoryReviewUser"] as SpectrumData.SpectrumTS.InventoryReviewUser).EmployeeId,
WorkDate = beginning
};
if (listOfTimeWorked.Contains(dayWorked) == false)
{
listOfTimeWorked.Add(dayWorked);
}
beginning = beginning.AddDays(1);
}
return View(listOfTimeWorked);
}
[HttpPost]
public ActionResult CreateTimeWorkedRange(List<Models.TimeWorked> modelList)
{
foreach (Models.TimeWorked timeWorked in modelList)
{
Models.TimeWorked.CreateTimeWorked(timeWorked);
}
}
I don't know if there's a better way, but one way to do this is to bind your items using the index of the array as follows:
#for (int i = 0; i < Model.Count; ++i) {
<tr>
#Html.HiddenFor(modelItem => Model[i].EmployeeId)
<td>
#Html.TextBoxFor(modelItem => Model[i].WorkDate)
</td>
<td>
#Html.TextBoxFor(modelItem => Model[i].HoursWorked)
</td>
<td>
#Html.HiddenFor(modelItem => Model[i].BeenSubmitted)
</td>
</tr>
}
You'd need a different collection type for your model (IList<TimeWorked> should be fine) to be able to use indexers, but that shouldn't be a problem I'd imagine. When you post, the collection should fill properly.
I have two forms on one View executing two separate Action methods in one Controller.
The first form (frmRefresh) is responsible for getting data and displaying it on the form so the user can pick certain checkboxes. Once submitted, the data is returned just fine in the ViewModel and is properly displayed on the form. 11 records for the Templates and 3 records for the Guarantors are displyaed as checkboxes on the form.
The second form (frmProcess), is responsible for taking the data on the form (that came back from the first post above). The user makes selections on the screen and processes it against some logic in the Controller. I have List objects in the model and don't suppose I can use the FormCollection to process the data because of the complex objects. Basically, they are a collection of checkboxes. I really need to use the data that should be submitted in the Model because of processing in the Controller for that data.
When submitting the second form, I realize that the loanid & ddl will not be available unless I put them in a hidden field (because they are in a separate form) --- that's fine. What I'm having a great deal of difficulty in understanding is when I submit the second form (frmProcess), why doesn't the model view binder take the data from the form, put it in the model and submit it to my GeneratePDF action method.?
Number one, I really need some help in understanding why this is happening and number two, I really need a soltution which takes my model data from the form to the action method and processes it. As you can see in the Controller, at the end of the code, I'm enumerating the Templates in the ViewModel to process the data.
Please help, as I am totally stuck on this at work and they are depending on me for this. I just don't get why the model binder doesn't take the values on the form and submit it to the action method for processing. It appears I'm missing something to allow the data to get back into the Model upon submission.
Below is my pertinent code:
ViedwModel
public partial class ViewModelTemplate_Guarantors
{
public int SelectedTemplateId { get; set; }
public IEnumerable<PDFTemplate> Templates { get; set; }
public int SelectedGuarantorId { get; set; }
public IEnumerable<tGuarantor> Guarantors { get; set; }
public string LoanId { get; set; }
public string SelectedDeptText { get; set; }
public string SelectedDeptValue { get; set; }
public string LoanType { get; set; }
public bool ShowTemps { get; set; }
public string Error { get; set; }
public string ErrorT { get; set; }
public string ErrorG { get; set; }
public bool ShowGeneratePDFBtn { get; set; }
}
View
#model PDFConverterModel.ViewModels.ViewModelTemplate_Guarantors
#{
ViewBag.Title = "BHG :: PDF Generator";
}
<h2>#ViewBag.Message</h2>
<div>
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("Refresh", "Home", FormMethod.Post, new { id = "frmRefresh" })) { <tr>
<td>
#*#(Html.Kendo().NumericTextBox<int>()
.Name("txtLoanID")
.Placeholder("Enter numeric value")
)*#
#Html.LabelFor(model => model.LoanId)
#Html.TextBoxFor(model => model.LoanId)
#Html.ValidationMessageFor(model => model.LoanId)
</tr>
<tr>
<td>#Html.LabelFor(model => model.LoanType)
#Html.TextBox("SBA", "SBA")
#Html.ValidationMessageFor(model => model.LoanType)
#*#Html.TextBoxFor(model => model.LoanType)*#
</td>
<td>
<label for="ddlDept">Department:</label>
#(Html.Kendo().DropDownListFor(model => model.SelectedDeptText)
.Name("ddlDept")
.DataTextField("DepartmentName")
.DataValueField("DepartmentID")
.Events(e => e.Change("Refresh"))
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetDepartments", "Home");
});
})
)
#Html.ValidationMessageFor(model => model.SelectedDeptText)
</td>
</tr>
<tr>
<td colspan="3">
<input type="submit" id="btnRefresh" value='Refresh' />
</td>
</tr>
}
#using (Html.BeginForm("GeneratePDF", "Home", FormMethod.Post, new { id = "frmProcess" })) { if (Model.ShowGeneratePDFBtn == true)
{
if (Model.ErrorT != string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Templates:")</b></u>
</td>
</tr>
<tr>
#foreach (var item in Model.Templates)
{
<td>
#Html.CheckBoxFor(model => item.IsChecked)
#Html.DisplayFor(model => item.TemplateName)
</td>
}
</tr>
}
else
{
Model.Error = Model.ErrorT;
}
if (Model.ErrorG != string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Guarantors:")</b></u>
</td>
</tr>
<tr>
#foreach (var item in Model.Guarantors)
{
<td>
#Html.CheckBoxFor(model => item.isChecked)
#Html.DisplayFor(model => item.GuarantorFirstName) #Html.DisplayFor(model => item.GuarantorLastName)
</td>
}
</tr>
}
else
{
Model.Error = Model.ErrorG;
}
<tr>
<td>
<input type="submit" id="btnGeneratePDF" value='Generate PDF' />
</td>
</tr>
<tr>
<td colspan="5">
#Model.Error
</td>
</tr>
}
} </table>
</div>
<script type="text/javascript">
$('btnRefresh').on('click', '#btnRefresh', function () {
Refresh();
});
function Refresh() {
var LoanID = $("#LoanID").val();
if (LoanID != "") {
document.forms["frmTemps"].submit();
}
}
</script>
Controller
public ActionResult Index(ViewModelTemplate_Guarantors model)
{
ViewBag.Error = "";
model.ShowGeneratePDFBtn = false;
return View("Index", model);
}
// used for the first form "frmRefresh" [HttpPost] public ActionResult Refresh(ViewModelTemplate_Guarantors model) {
try
{
model.Error = string.Empty;
bool dbHasRows = db.ChkLoanFields(Convert.ToInt32(model.LoanId));
if (!dbHasRows)
{
model.ShowGeneratePDFBtn = false;
model.Error = "Details not available for this LoanId.";
return View("Index",model);
}
else
{
int TemplateCnt = 0;
int GuarantorCnt = 0;
//todo - modify 2nd & 3rd parms instead of hardcoding
ViewModelTemplate_Guarantors tg = db.SelectViewModelTemplate_Guarantors(Convert.ToInt32(model.LoanId), "All", "All", out TemplateCnt, out GuarantorCnt);
if (TemplateCnt > 0)
model.Templates = tg.Templates;
else
model.ErrorT = "Templates not available for this LoanType.";
if (GuarantorCnt > 0)
model.Guarantors = tg.Guarantors;
else
model.ErrorG = "Guarantors not available for this LoanId.";
model.ShowGeneratePDFBtn = true;
// right before the return here, the model is full of data. return View("Index", model); }
}
catch (Exception ex)
{
throw ex;
}
} [HttpPost] // when I check the data here (via submission from the "frmProcess" form, the model is completely empty, null, etc... WHY???? // i NEED the model data here to perform processing in this action method. public ActionResult GeneratePDF(ViewModelTemplate_Guarantors model) {
try
{
int FolderNo, GuarantorNum = 0;
string Folder, LoanFolder = String.Empty;
string FormId, FormName, GuarantorName = String.Empty;
int LoanId = Convert.ToInt32(model.LoanId);
LoanFolder = LoanId.ToString().PadLeft(8, '0');
//To calculate FolderId based on LoanId
if ((LoanId > 0) && (LoanId < 99000))
{
FolderNo = ((int)(LoanId / 10000) * 10000);
}
else
{
FolderNo = ((int)(LoanId / 1000) * 1000);
}
Folder = ((int)FolderNo).ToString();
Folder = Folder.PadLeft(8, '0');
//todo - 2nd parm SelectedValue of dept
List<sSRPTFundexDocCodes1_Test_Result> sSRPTFundexDocCodes1 = db.GetFormValues(Convert.ToInt32(model.LoanId), (model.SelectedDeptValue));
if (sSRPTFundexDocCodes1 != null)
{
foreach (PDFTemplate template in model.Templates) {
if (template.IsChecked == true) {
TemplateName not showing up in model after post.
This works fine... The values (the checkboxes and the corresponding names are displyaed on the form.
However, when posting the GeneratePDF button, all I see in the model is if the Checkbox is checked (which is great). After playing around with many of the following statements: (ValueFor, DisplayFor, LabelFor, EditorFor, etc), the value coming back for the Template name is blank. I need the name of the template that was checked in correspondance with the checkbox.
#Html.ValueFor(model => Model.Templates[i].TemplateName)
How can I accomplish this? Thanks ahead of time... Below is my updated code.
ViewModel public partial class ViewModelTemplate_Guarantors
{
public ViewModelTemplate_Guarantors()
{
Templates = new List<PDFTemplate>();
Guarantors = new List<tGuarantor>();
}
public int SelectedTemplateId { get; set; }
public List<PDFTemplate> Templates { get; set; }
public int SelectedGuarantorId { get; set; }
public List<tGuarantor> Guarantors { get; set; }
public string LoanId { get; set; }
public string SelectedDeptText { get; set; }
public string SelectedDeptValue { get; set; }
public string LoanType { get; set; }
public string Error { get; set; }
public string ErrorT { get; set; }
public string ErrorG { get; set; }
public bool ShowGeneratePDFBtn { get; set; }
}
Pertinet part of View:
if (Model.ShowGeneratePDFBtn == true)
{
if (Model.ErrorT == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Templates:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Templates.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Templates[i].IsChecked)
#Html.ValueFor(model => Model.Templates[i].TemplateName) </td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorT)</b>
</td>
</tr>
}
if (Model.ErrorG == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Guarantors:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Guarantors.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Guarantors[i].isChecked)
#Html.ValueFor(model => Model.Guarantors[i].GuarantorFirstName) #Html.ValueFor(model => Model.Guarantors[i].GuarantorLastName) </td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorG)</b>
</td>
</tr>
}
}
<tr>
<td colspan="3">
<input type="submit" name="submitbutton" id="btnRefresh" value='Refresh' />
</td>
#if (Model.ShowGeneratePDFBtn == true)
{
<td>
<input type="submit" name="submitbutton" id="btnGeneratePDF" value='Generate PDF' />
</td>
}
</tr>
<tr>
<td colspan="5">
#Model.Error
</td>
</tr>
Controller:
public ActionResult ProcessForm(string submitbutton, ViewModelTemplate_Guarantors model, FormCollection collection)
Basically, again it's working fine. When the form posts using the Generate PDF button, I get the checked value of each checkbox, but not the name of the template in the Model.
Am I missing something here???
The form before I submit is basically like below. It's the name of the checkbox (Form4) that I'm missing as a TemplateID in my Model once I get into the ActionResult.
public ActionResult ProcessForm(string submitbutton, ViewModelTemplate_Guarantors model, FormCollection collection)
checkbox (checked) Form4
#for (int i = 0; i < Model.Templates.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Templates[i].IsChecked)
#Html.DisplayFor(model => Model.Templates[i].TemplateName)
</td>
}
As I mentioned in my comment. The model binder cannot bind to an IEnumerable.
Your Model should look like this:
public partial class ViewModelTemplate_Guarantors
{
public ViewModelTemplate_Guarantors() {
Templates = new List<PDFTemplate>(); // These are important, the model binder
Guarantors = new List<tGuarantor>(); // will not instantiate nested classes
}
public int SelectedTemplateId { get; set; }
public List<PDFTemplate> Templates { get; set; }
public int SelectedGuarantorId { get; set; }
public List<tGuarantor> Guarantors { get; set; }
...
}
Further, your view should look like this:
...
#for(int i = 0; i < Model.Templates.Count; i++) // should really use label, not display
{
<td>
#Html.CheckBoxFor(model => Model.Templates[i].IsChecked)
#Html.DisplayFor(model => Model.Templates[i].TemplateName)
</td>
}
...
#for(int i = 0; i < Model.Guarantors.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Guarantors[i].isChecked)
#Html.DisplayFor(model => Model.Gurantors[i].GuarantorFirstName) #Html.DisplayFor(model => Model.Guarantors[i].GuarantorLastName)
</td>
}
...
Although a better choice would be to use an EditorTemplate and instead do this:
...
#Html.EditorFor(m => m.Templates)
...
#Html.EditorFor(m => m.Guarantors)
...
Then create a folder in ~/Views/Shared called EditorTemplates, and then create two files called Templates.cshtml and Guarantors.cshtml.
In those files you would do this:
#model PDFTemplate
<td>
#Html.CheckBoxFor(model => model.IsChecked)
#Html.DisplayFor(model => model.TemplateName)
</td>
and
#model Guarantors
<td>
#Html.CheckBoxFor(model => model.isChecked)
#Html.DisplayFor(model => model.GuarantorFirstName) #Html.DisplayFor(model => model.GuarantorLastName)
</td>
The editor templates will automatically iterate over the collection and will account for the correct naming format to make the model binder understand it's a collection.