I am busy with trying to greet a person in the email, this email body is made from an html script but the issue i am having is that it prints out the variable name instead of the value itself.
Here is my controller:
public async Task<IHttpActionResult> EmailReport([FromUri] ReportRequestViewModel request)
{
var reportEmailViewModel = new ReportEmailViewModel();
reportEmailViewModel.Name = CurrentUser.Name;
reportEmailViewModel.ScorecardName = _BEEScorecardService.GetById(request.ScorecardId).Name;
var pdf = GetFileAsResponseMessage(docStream.ToArray(), report.FileName, true);
var encoding = new System.Text.UTF8Encoding();
var newReportEmail = new ReportEmailModel()
{
ToRecieverEmailAddress = CurrentUser.Email,
Body = (System.IO.File.ReadAllText(HttpContext.Current.Server.MapPath("/Views/EmailTemplate/")+ "ReportEmail.cshtml", encoding)),
attachment = pdf
};
_EmailService.SendReportEmail(newReportEmail);
return Ok();
}
My viewmodel for the persons name and other details:
public class ReportEmailViewModel
{
public string Name { get; set; }
public string ScorecardName { get; set; }
}
and my chtml(I cut out some of the html to show exactly where the error is occuring):
#model BEE123.Web.UI.ViewModel.ReportEmailViewModel
<!DOCTYPE html>
<html>
<body>
<div align='center'>
<table class='MsoNormalTable' style='width:462.0pt;mso-cellspacing:1.5pt;mso-yfti-tbllook:1184' width='616'
cellspacing='3' cellpadding='0' border='0'>
<tbody>
<tr style='mso-yfti-irow:0;mso-yfti-firstrow:yes;mso-yfti-lastrow:yes'>
<td style='padding:.75pt .75pt .75pt .75pt'>
<p class='MsoNormal'>
<span style='font-size:8.5pt;font-family:"Segoe UI",sans-serif;mso-fareast-font-family:"Times New Roman"'>
<img id='_x0000_i1025'
src='http://app.bee123.co.za/Images/BEE123EmailBanner.PNG' ?=''>
</span>
</p>
<h1>
<span style='font-family:"Segoe UI",sans-serif;mso-fareast-font-family:"Times New Roman";color:#B8995F'>Scorecard Report</span>
</h1>
<p>
<span style='font-size:8.5pt;font-family:"Segoe UI",sans-serif'>
Hi #Model.Name
</span>
</p>
But this is what shows in the email:
Related
I am new to ASP.NET but have done 20 years of desktop dev. I have a Customer class with fields CustId, CustName, CustNotes.
I have a view called CustView that has some input boxes that are to be pre-populated with customer details from a previous view using the CustID.
I can show the customer details in the text boxes but I cannot get the user edited textboxes (ie the user changes the name of a customer) back to a stored procedure in an Action.
I use a DB class called Cust1DBHandle to call the stored procedure. I have set up 3 buttons and 3 actions in a bid to get any of them to work, either by passing variables or using RequestString but nothing works.
Question #1: how can I pass the new text values back as either global variables, variables in the action or using a datamodel?
Question #2: in the CustViewDBHandle, I populate a list of the results. Is that the correct thing to do if it’s only for one row of data?
Question #3: when pressing a SAVE button that executes a stored procedure, do you have to have a return in the action in the controller?
Thanks.
Cust.cs model
public partial class Cust
{
[DisplayName("Cust ID")]
public Int32 CustID { get; set; }
[DisplayName("Customer Name")]
// [Required(ErrorMessage = "This field is required")]
public string CustName { get; set; }
[DisplayName("Customer Notes")]
public string CustNotes { get; set; }
public string ErrorMessageCust { get; set; }
}
CustView.cshtml:
#model IEnumerable<App22.Models.Cust>
#{
ViewBag.Title = "CustView";
}
<h2>#ViewBag.Title.</h2>
<h3>#ViewBag.Message</h3>
<header>
</header>
<meta name="viewport" content="width=device-width" />
<title>CustViewy</title>
<html>
<head>
</head>
<style>
th, td {
padding: 5px;
}
</style>
<body>
<p>
</p>
<p>CUSTOMER DETAILS ARE HERE</p>
<form name="1" method="post">
<fieldset>
<legend>Headline Details</legend>
<table>
#foreach (var item in Model)
{
<tr>
<td>
<label for="CustID">CustID:</label>
</td>
<td>
<input type="text" name="1CustID" value="#Html.DisplayFor(modelItem =>
item.CustID)" />
</td>
</tr>
<tr>
<td>
<label for="CustName">CustName:</label>
</td>
<td>
<input type="text" name="2CustName" value="#Html.DisplayFor(modelItem
=> item.CustName)" />
</td>
</tr>
<td>
<label for="CustNotes">Cust Notes:</label>
</td>
<td>
<input type="text" name="3CustNotes" value="#Html.DisplayFor(modelItem =>
item.CustNotes)" />
</td>
<tr>
<td></td>
<td>
<input type="submit" name="action:Save1" value="Save" />
<button style="background-color:red" type="button" name="tree0"
class="btn btn-primary" onclick="location.href='#Url.Action("SaveCust0","Cust1")'">
SAVE0 »
</button>
<button style="background-color:blue" type="button" name="tree1"
class="btn btn-primary" onclick="location.href='#Url.Action("SaveCust1","Cust1",new { CustyIDSave = item.CustID , CustyNameSave = item.CustName })'">
SAVE1 »
</button>
<button style="background-color:green" type="button" name="tree2" class="btn btn-primary" onclick="location.href='#Url.Action("SaveCust2","Cust1")'">
SAVE2 »
</button>
</td>
<td>
</td>
</tr>
}
</table>
</fieldset>
</form>
</body>
</html>
Cust1Controller.cs:
public class Cust1Controller : Controller
{
public ActionResult SaveCust0()
{
string message = "";
message = Request.Form["CustName"].ToString();
return Content(message);
CustViewDBHandle dbhandle = new CustViewDBHandle();
ModelState.Clear();
dbhandle.SaveCust(Convert.ToInt32(Request.Form["CustID"]),
Request.Form["CustName"].ToString());
}
public ActionResult SaveCust1(int CustyIDSave, string CustyNameSave)
{
CustViewDBHandle dbhandle = new CustViewDBHandle();
ModelState.Clear();
dbhandle.SaveCust(CustyIDSave, CustyNameSave);
return null;
}
[HttpPost]
public ActionResult SaveCust2(int CustyIDSave, string CustyNameSave)
{
CustViewDBHandle dbhandle = new CustViewDBHandle();
ModelState.Clear();
dbhandle.SaveCust(CustyIDSave, CustyNameSave);
return null;
}
// GET: Cust1
public ActionResult Index()
{
Cust1DBHandle dbhandle = new Cust1DBHandle();
ModelState.Clear();
return View("~/Views/Cust/Cust1.cshtml",dbhandle.GetCust(""));
// return View("~/Views/Cust/Cust1.cshtml"); //This works
}
[HttpGet]
public ActionResult Reload(string tree)
{
//tree = "Breaker2";
Cust1DBHandle dbhandle = new Cust1DBHandle();
ModelState.Clear();
return View("~/Views/Cust/Cust1.cshtml", dbhandle.GetCust(tree));
//Cust1DBHandle dbhandle = new Cust1DBHandle();
//ModelState.Clear();
//return View("~/Views/Cust/Cust1.cshtml", dbhandle.GetCust(SearchBy));
// return View("~/Views/Cust/Cust1.cshtml"); //This works
}
public ActionResult ViewCust(int CustyIDView)
{
//tree = "Breaker2";
CustViewDBHandle dbhandle = new CustViewDBHandle();
ModelState.Clear();
return View("~/Views/Cust/CustView.cshtml", dbhandle.GetCust(CustyIDView));
//Cust1DBHandle dbhandle = new Cust1DBHandle();
//ModelState.Clear();
//return View("~/Views/Cust/Cust1.cshtml", dbhandle.GetCust(SearchBy));
// return View("~/Views/Cust/Cust1.cshtml"); //This works
}
}
CustViewDBHandle.cs:
public class CustViewDBHandle
{
// ********** VIEW CUSTOMER DETAILS ********************
public List<Cust> GetCust(int CustyID)
{
GlobalVar.connection();
List<Cust> CustyChosen = new List<Cust>();
SqlCommand cmd = new SqlCommand("psv_CustView1", GlobalVar.con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CustyID", CustyID);
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
GlobalVar.con.Open();
sd.Fill(dt);
GlobalVar.con.Close();
foreach (DataRow dr in dt.Rows)
{
CustyChosen.Add(
new Cust
{
CustID = Convert.ToInt32(dr["CustID"]),
CustName = Convert.ToString(dr["CustName"]),
CustNotes = Convert.ToString(dr["CustNotes"]),
});
GlobalVar.GlobCustName1 = Convert.ToString(dr["CustName"]); //This method uses
Global Var to get data to pass to form. Can pass anything that way.
}
return CustyChosen;
}
public int SaveCust(int CustyID, string CustyName)
{
GlobalVar.connection();
SqlCommand cmd = new SqlCommand("psu_CustSave1", GlobalVar.con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#CustyID", CustyID);
cmd.Parameters.AddWithValue("#CustyName", CustyName);
GlobalVar.con.Open();
cmd.ExecuteNonQuery();
//SqlDataAdapter sd = new SqlDataAdapter(cmd);
//DataTable dt = new DataTable();
//sd.Fill(dt);
GlobalVar.con.Close();
return 1;
}
}
There is a lot to parse here, but what strikes me as the main part of the problem you have noted is:
a) You methods on the controller are not all decorated with HttpPost attributes.
b) The action on the form that you render will be looking for a POST endpoint with a name that matches the get
That said, you're going to find it hard to get answers for how to make this work, given that this is very non-idiomatic asp.net MVC code.
I would strongly suggest working through a few tutorials, as web dev is considerably different to windows dev, with a different set of challenges. Hopefully your experience will let you skim through that quickly.
I'm new to the world of ASP.Net MVC and I'm working with a small application that uses many XML files from a web service as its model data. I have an Html page which contains a list of all the tools that are stored in the XML web services. They are within a loop and are clickable links. I also have a partial view which is just a series of text boxes. My goal is to populate the text boxes with information I get from the tool I click while having the list and the text boxes appear on the same page. I have been successful in doing this but so far have only been able to pass the id to a controller which returns my partial view as a completely new page. I'm sure this is a simple solution which may have been answered on here before. What is the best way to go about solving this problem? Below is my model, view(s) and two controllers
Tool Model
public class Tool
{
public int Id { get; set; }
public string ToolId { get; set; }
public string Adapter { get; set; }
public string Description { get; set; }
public string TNumber { get; set; }
public List<string> ComponentList { get; set; }
public List<string> AccessoryList { get; set; }
public List<KeyValuePair<string, string>> ToolIdDescription { get; set; }
public List<string> toolList = new List<string>();
}
Partial View Controller
public ActionResult PartialView()
{
Tool newTool = new Tool();
List<string> tools = new List<string>();
tools = backgroundLoad();
newTool.ToolIdDescription = new List<KeyValuePair<string, string>>();
atool.ToolIdDescription = new List<KeyValuePair<string, string>>();
foreach (string tool in tools)
{
newTool.ToolIdDescription = GetToolDescription(tool);
}
return View(newTool);
}
Controller to recieve Datasets
public ActionResult GetDataSet(string id)
{
Tool selectedTool = new Tool();
if (id != null)
{
var request =
(HttpWebRequest)WebRequest.Create("http://localhost/DbService/Tool/" + id);
XmlDocument xml = new XmlDocument();
Stream aResponsestream;
string aResult = "";
using (aResponsestream = request.GetResponse().GetResponseStream())
using (StreamReader aReader = new StreamReader(aResponsestream,
Encoding.UTF8))
{
aResult = aReader.ReadToEnd();
aResponsestream.Close();
}
xml.LoadXml(aResult);
var Description =
xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/Description");
if (Description != null) selectedTool.Description =
Description.InnerText;
var Adapter =
xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/Adapter/Name");
if (Adapter != null) selectedTool.Adapter = Adapter.InnerText;
var TNumber =
xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/TNo");
if (TNumber != null) selectedTool.TNumber = TNumber.InnerText;
var ToolId =
xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/ToolId");
if (ToolId != null) selectedTool.ToolId = ToolId.InnerText;
return View(selectedTool);
}
else return View();
}
View which contains the list
#model MiniWeb.Models.Tool
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="~/Content/Site.css" rel="stylesheet" />
</head>
<body>
<h2>Tool List</h2>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Id</th>
<th>Description</th>
</tr>
</thead>
#foreach (var item in Model.ToolIdDescription)
{
<tbody>
<tr>
<td>#Html.ActionLink(item.Key, "GetDataSet", new { id = item.Key })</td>
<td>#Html.DisplayFor(modelItem => item.Value)</td>
</tr>
</tbody>
}
</table>
</div>
</body>
</html>
#Html.Partial("GetDataSet", new MiniWeb.Models.Tool())
View which displays the tool information
#model MiniWeb.Models.Tool
#{
ViewBag.Title = "GetDataSet";
}
#{
ViewBag.Title = "Tool";
}
<link href="~/Content/Site.css" rel="stylesheet" />
<h2>Tool Selection </h2>
<div class="Tool">
<span id ="id">
#Html.LabelFor(m => Model.ToolId)
#Html.TextBoxFor(modelItem => Model.ToolId)
</span>
<br/>
<span id="Description">
#Html.LabelFor(m => Model.Description)
#Html.TextBoxFor(modelItem => Model.Description)
</span>
<br/>
<span id="Adapter">
#Html.LabelFor(m=> Model.Adapter)
#Html.TextBoxFor(modelItem => Model.Adapter)
</span>
<br/>
<span id="Adapter">
#Html.LabelFor(m => Model.TNumber)
#Html.TextBoxFor(modelItem => Model.TNumber)
</span>
<span>
<button> Save </button>
</span>
</div>
Sorry for all the code but thank you for reading. I also apologize if this is a really easy solution. I'm just new to ASP.Net and want to develop the best practices instead of doing a hack job on it. Thanks for the help.
With some more research I was able to figure out how to solve my problem. Turns out all I needed was some AJAX. I used an Ajax.Actionlink instead of an HTML action link and was able to load up my partial view in a div on the page. Here is my new view and controller. The partial view stayed the same.
View
#model MiniWeb.Models.Tool
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="~/Content/Site.css" rel="stylesheet" />
<script src="~/Scripts/jquery-3.1.1.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
</head>
<body>
<h2>Tool List</h2>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Id</th>
<th>Description</th>
</tr>
</thead>
#foreach (var item in Model.ToolIdDescription)
{
<tbody>
<tr>
<td>#Ajax.ActionLink(item.Key, "_Partially", new { id = item.Key },new AjaxOptions()
{
HttpMethod = "GET",
UpdateTargetId = "ToolInfo",
InsertionMode = InsertionMode.Replace,
})
</td>
<td>#Html.DisplayFor(modelItem => item.Value)</td>
</tr>
</tbody>
}
</table>
</div>
</body>
</html>
<div id="ToolInfo">
</div>
and my new controller which is returns a PartialView looks like this
Partial View Controller
public PartialViewResult _Partially(string id)
{
Tool selectedTool = new Tool();
if (id != null)
{
var request = (HttpWebRequest)WebRequest.Create("http://localhost/DbService/Tool/" + id);
XmlDocument xml = new XmlDocument();
Stream aResponsestream;
string aResult = "";
using (aResponsestream = request.GetResponse().GetResponseStream())
using (StreamReader aReader = new StreamReader(aResponsestream, Encoding.UTF8))
{
aResult = aReader.ReadToEnd();
aResponsestream.Close();
}
xml.LoadXml(aResult);
var Description = xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/Description");
if (Description != null) selectedTool.Description = Description.InnerText;
var Adapter = xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/Adapter/Name");
if (Adapter != null) selectedTool.Adapter = Adapter.InnerText;
var TNumber = xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/TNo");
if (TNumber != null) selectedTool.TNumber = TNumber.InnerText;
var ToolId = xml.SelectSingleNode("RetrieveResponse/RetrieveResult/Tool/ToolId");
if (ToolId != null) selectedTool.ToolId = ToolId.InnerText;
return PartialView("_Partially", selectedTool);
}
return PartialView();
}
Hopefully this answer will help others like me in the future. Thanks for reading.
You're going to want to create a form on your partial view that will submit the data to the main pages controller.
You can find more information in this article.
I am using Ajax to populate a partial view in my web application. This partial view contains a link to download a PDF file based upon the data that is currently in the table / List<> of the model.
The partial view is as follows:
#model Inspection_Reports.ViewModel.SummaryReportViewModel
<table id="summaryReportTable" class="table-condensed table-striped">
<thead><tr><td>Inspector</td><td>Attendant</td><td>Property</td><td>Room Number</td><td>Date</td><td>HK Score</td><td>Maint. Score</td></tr></thead>
<tbody id="resultsContainer">
#foreach (var report in #Model.reportsList)
{
<tr><td>#report.inspect.empName</td><td>#report.attendant.empName</td><td>#report.location.locName</td><td>#report.room</td><td>#report.endTime</td><td>#report.hkDisplay</td><td>#report.mainDisplay <input type='hidden' name='reportId[i]' /></td></tr>
}
</tbody>
</table>
#Html.ActionLink("Export as PDF", "GenerateSummaryPDF", new { summary = #Model.reportsList })
GenerateSummaryPDF method:
public FileResult GenerateSummaryPDF(List<report_summary> summary) {
Document doc = pdfWorker.readyDocument("Inspection Report, Generated " + DateTime.Now.ToString("MM-dd-yyyy"));
pdfWorker.createSummaryReport(doc, summary);
pdfWorker.savePDF(doc, String.Format("{0}/Inspection_Summary_{1}.pdf", #"C:\Users\Khandokar\Desktop", DateTime.Now.ToString("MM-dd-yyyy")));
return File(String.Format("{0}/Inspection_Summary_{1}.pdf", #"PATH", DateTime.Now.ToString("MM-dd-yyyy")), "application/pdf", "Inspection.pdf");
The problem is that, when the GenerateSummaryPDF is called, the summary list is empty. The list is not null, but merely has no items in it.
However, I am not sure why this is the case. When I click the export link, there is data in Model.reportsList; it is visible in the table and further verified by setting a breakpoint.
The parent view:
#model Inspection_Reports.ViewModel.SummaryReportViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Report Summaries</title>
</head>
<body>
<h2>Summary Reports</h2>
<form class="form-horizontal">
<div class="form-group"><label class="control-label col-md-2">Start Date: </label><div class="col-md-4"><input class="form-control summaryFilter" type='text' value="#Model.fromDate" name='startDate' id='startDate' /></div><label class="control-label col-md-2">End Date: </label><div class="col-md-4"><input type='text' value="#Model.toDate" class='form-control summaryFilter' name='endDate' id='endDate' /></div></div>
<div class="form-group">
<label class="control-label col-md-2">Filter By: </label>
<div class="col-md-4">
<select class="form-control summaryFilter" name="filterTypeList" id="filterTypeList">
<option value="">Select...</option>
<option value="Property">Property</option>
<option value="Attendant">Attendant</option>
<option value="Inspector">Inspector</option>
</select>
</div>
<label class="control-label col-md-2">Filter Selection: </label><div class="col-md-4">
<select class="form-control summaryFilter" name="filterSelectionList" id="filterSelectionList"></select>
</div>
</div>
</form>
<div id="reportResults">
#{Html.RenderPartial("SummaryPartialView", Model);}
</div>
#section scripts {
<script src="~/Scripts/ajaxReports.js"></script>
}
</body>
</html>
The methods used to populate the partial view (based largely on this article: https://cmatskas.com/update-an-mvc-partial-view-with-ajax/)
[HttpGet]
public async Task<ActionResult> GetSummaryReports(string fromDate, string toDate, string filterType, string filterValue)
{
DateTime from = Convert.ToDateTime(fromDate);
DateTime to = Convert.ToDateTime(toDate);
Int32 filterValID = Int32.Parse(filterValue);
SummaryReportViewModel vm = await GetSummaryVM(from, to, filterType, filterValID);
return PartialView("SummaryPartialView", vm);
}
private async Task<SummaryReportViewModel> GetSummaryVM(DateTime from, DateTime to, string filterType, int filterValID)
{
SummaryReportViewModel vm = new SummaryReportViewModel();
to = to.AddDays(1);
var reports = dbContext.report_summary.Where(r => r.endTime <= to && r.endTime >= from);
if (filterType.Equals("Property"))
{
reports = reports.Where(r => r.locationID == filterValID);
}
else if (filterType.Equals("Attendant"))
{
reports = reports.Where(r => r.employee == filterValID);
}
else
{
reports = reports.Where(r => r.inspector == filterValID);
}
vm.reportsList = reports.ToList<report_summary>();
return vm;
}
The Ajax
$(".summaryFilter").change(function () {
var fromDate = $("#startDate").val();
var toDate = $("#endDate").val();
var filterType = $("#filterTypeList").val();
var filterValue = $("#filterSelectionList").val();
if (filterValue != null || typeof (filterValue) != typeof (undefined)) {
$.ajax({
url: "GetSummaryReports?fromDate=" + fromDate + "&toDate=" + toDate + "&filterType=" + filterType + "&filterValue=" + filterValue,
type: 'get',
success: function (data) {
$("#reportResults").html(data);
},
});
}
});
Thanks for any help.
You're asking a bit much of a Get method - you should instead switch to a form that Posts to allow model binding to handle your complex list object.
I am at very basic stage of asp.net MVC development. So sometimes I struggle with simple LINQ queries to work.
scenario-
I have A page that has some Image and comment on that Image by users (Just Like a post on facebook containing comments from users).
So I am saving those comments from the textarea and sending Image ID via Ajax query.
Here Is my controller action method-
Saving comment-
[HttpPost]
public void SaveComment(CardModel card) {
CardCommentTable commenttable = new CardCommentTable();
commenttable.CardComment = card.cardComment;
commenttable.FKcardID = card.cardID;
db.CardCommentTables.InsertOnSubmit(commenttable);
db.SubmitChanges();
}
This Comment is saved in CardCommentTable that has foreign key reference of Table in that Image is saved.
Rendering Image and other fields on view page-
This query renders Image and other fields that make it An Image post. Like title, dateofsubmit, Like etc.
public ActionResult CardDetails(CardModel card) {
var cardDetail = (from u in db.CardTables
where u.CardID == card.cardID
select new CardModel {
cardID = u.CardID,
cardHashCode = u.CardHashCode,
cardDate = u.CardDate,
cardFileName = u.CardFileName,
cardFilePath = u.CardFilePath,
cardTitle = u.CardTitle
}).ToList();
return View(cardDetail);
}
Now In cardTable I have one more column named cardComment in that I want to show all those saved comments from table CardCommentTable.
So I tried-
public ActionResult CardDetails(CardModel card) {
var allsavedcomments= (from u in db.CardCommentTables
where u.FKcardID == card.cardID
select u).ToList();
var cardDetail = (from u in db.CardTables
where u.CardID == card.cardID
select new CardModel {
cardID = u.CardID,
cardHashCode = u.CardHashCode,
cardDate = u.CardDate,
cardFileName = u.CardFileName,
cardFilePath = u.CardFilePath,
cardTitle = u.CardTitle,
cardComment = allsavedcomments // Trying to render all saved coments here.
}).ToList();
return View(cardDetail);
}
View-
#model IEnumerable<FunRanger.Models.CardModel>
#foreach (var item in Model) {
<script type="text/javascript">
$(function () {
$('#save-comment').click(function () {
var textareavalue = $('#textarea-comment').val();
$.ajax({
url: '/Home/SaveComment/',
type: 'post',
data: '&cardComment=' + textareavalue + '&cardID=' + '#item.cardID',
success: function (data) {
$('#all-comments').append(data);
}
});
});
});
</script>
using (Html.BeginForm()) {
#Html.ValidationSummary(true)
#if (Model != null) {
<h2 class="header-wrapmain">
#item.cardTitle
</h2>
#item.cardDate.ToShortDateString()
<img src="#item.cardFilePath" />
<a href="#" class="#item.cardHashCode" rel="tooltip" data-placement="bottom" title="Filter by #item.cardHashCode">
##item.cardHashCode</a>
}
else {
<div class="alert alert-danger">
No More items to preview
</div>
}
}
<textarea class="span12" rows="5" id="textarea-comment" style="resize: none" placeholder="Enter a comment..."></textarea>
Save comment
<ol>
<li>
#item.cardComment
</li>
</ol>
}
How can I insert List result in a column here.
How do I show all saved comments with this above query?
Thanks for any help.
I slightly renovated your code with Foreign key relations ship. This will save your from using two different queries to your database (like what you are doing now).
So if you Database Model looks like this -
Then you should have one viewmodel in your code in this way -
public class ImageViewModel
{
public string ImageId { get; set; }
public string ImageUrl { get; set; }
public List<string> Comments { get; set; }
}
And your controller action which will return all the results should be like this -
public class ListController : Controller
{
public ActionResult Index()
{
ImageViewModel model;
using (SampleEntities entities = new SampleEntities())
{
model = (from p in entities.Images
where p.ImageId == "1"
select new ImageViewModel()
{
ImageId = p.ImageId,
ImageUrl = p.ImageUrl,
Comments = p.ImageComments.Select(pa => pa.Comment).ToList()
}).FirstOrDefault();
}
return View(model);
}
}
Finally the view which will display all the Image results -
#model MVC.Controllers.ImageViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<div>
<h4>ImageViewModel</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.ImageId)
</dt>
<dd>
#Html.DisplayFor(model => model.ImageId)
</dd>
<dt>
#Html.DisplayNameFor(model => model.ImageUrl)
</dt>
<dd>
#Html.DisplayFor(model => model.ImageUrl)
</dd>
<br/>
#foreach (var item in Model.Comments)
{
#item <br/>
}
</dl>
</div>
Output would be -
Your cardComment property is a list of strings; it needs to be iterated in order to be displayed. Replace:
<ol>
<li>
#item.cardComment
</li>
</ol>
with:
<ol>
#foreach (var singleComment in Model.cardComment)
{
<li>#singleComment </li>
}
</ol>
I have the following Model :
public class FileModel
{
public int Id { get; set; }
[Required(ErrorMessage = "Required")]
[StringLength(100, ErrorMessage = "Max is 100, Min is 3", MinimumLength = 3)]
public string Name { get; set; }
public string Path { get; set; }
[Required(ErrorMessage = "Required")]
public string FileTypeId { get; set; }
public DateTime RegistrationDate { get; set; }
}
the following is my view :
#using (Html.BeginForm("Index", "FileManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table class="content-table" style="min-width: 600px; border-spacing: 15px;">
<tr>
<td colspan="4" class="table-header">New File
<div class="add-icon">+</div>
</td>
</tr>
<tr>
<td>Name: </td>
<td>#Html.TextBoxFor(q => q.NewFile.Name, new { maxlength = "100", id = "NewFile_Name1", name = "NewFile.Name1" })
<br />#Html.ValidationMessageFor(q => q.NewFile.Name)
</td>
<td>
<input type="file" id="FileUploadField1" /></td>
<td style="width: 16px; text-align: center;"> </td>
</tr>
<tr>
<td colspan="4" style="text-align: center;">
<input type="submit" value="Submit" />
</td>
</tr>
</table>
<script type="text/javascript">
$('.content-table .add-icon').click(function () {
var lastFileField = $('.content-table input[type="file"]').last();
var lastId = lastFileField.attr('id').replace(/\D*/g, '');
lastId = parseInt(lastId) + 1;
var newFields = '<tr>' +
'<td>Name : </td>' +
'<td><input data-val="true" data-val-length="Max chars is 100, Min chars is 3" data-val-length-max="100" data-val-length-min="3" data-val-required="Required" id="NewFile_Name' + lastId + '" name="NewFile.Name' + lastId + '" type="text" value="" /><br /><span class="field-validation-valid" data-valmsg-for="NewFile.Name' + lastId + '" data-valmsg-replace="true"></span></td>' +
'<td><input type="file" id="FileUploadField' + lastId + '"/></td>' +
'<td style="text-align:right;"><div class="delete-icon"></div></td>' +
'</tr>';
var lastTr = $(lastFileField).parents('tr:first')[0];
$(lastTr).after(newFields);
});
$('.content-table .delete-icon').live('click', function () {
$(this).parents('tr:first').remove();
});
</script>
}
As you can see, We have a form for uploading one or more files. So, I've added an + button for users that they can add a file field to form.
Users must enter the name of the file and select a file for uploading. But MVC client validator just validate the first inputs that added with Razor.
How can I force MVC validator to validate all fields at the client side and server side.
Another question is:
How can we handle getting the field values at a MVC Controller.
Thanks
This great blog will help you understand how the default model binder will bind lists and arrays. Just make a ViewModel for your page that looks somewhat like this:
public class FileUploadViewModel
{
public List<FileModel> lFileModels { get; set; }
}
Then in your "+" jQuery function, make sure the generated input names are something like lFileModels.[0].Title (or it might be lFileModels[0].Title, just click that link and you'll figure it out)
Then to get that info in the controller, it's just like any other form!
[HttpPost]
public ActionResult Index(FileUploadViewModel viewModel)
{
}
Edit
Another link for MVC file uploading
Edit 2
After reading your code once again, I now realise that the validation problem is due to adding unobtrusive validations after the library was loaded. You have to re-parse the validators.
$("form").data("validator", null);
$.validator.unobtrusive.parse($("form"));
The binding applies to server-side validation and the 2nd part of your question.
Edit 3
For adding fields, instead of doing it straight in JS, you should Ajax load the section of your form with the file fields. When you click on the add button, it request a partial view of the file fields with, in it's post data, a list of the current items. The partial view then returns a rendered view with an extra field. It's just an idea. I haven't tried or even seen that idea. I just though about it and figured I could share it.