how to transfer data from controller to view - asp.net

HomeController.cs
[HttpPost]
public ActionResult Index(int searchtext)
{
var data = (from pm in db.ProductMasters
join shi in db.SuppliersHotelsInfoes
on pm.ProductID equals shi.LocHotelID
where shi.SearchID == searchtext
select new {pm.ProductId,pm.Image,shi.HotelName,shi.HotelPrice}).ToList().Take(10);
ViewBag.Data = data;
return View();
}
Transfering the data to the view
<% try { %>
<tr><td>
<% foreach(var item in ViewBag.Data){ %>
<img alt="" src="<%= item. %>" />
</td><%} %> <% foreach(var item in ViewBag.Data) { %>
<td><%: Html.DisplayFor(modelItem => "")%></td>
<td><%: Html.DisplayFor(modelItem => "")%> </td>
<td><%: Html.DisplayFor(modelItem => "")%></td>
</tr>
<%} }%>
<%catch(Exception ex){ }%>
Here, how to get the values in "var item"

You really should use a ViewModel, I can't remember last time I used the ViewBag
I'm also going to use Razor here, its syntax is much more terse. You don't need to use DisplayFor if you're just presenting the data:
#foreach(var item in ViewBag.Data){
<tr>
<td><img alt="" src="#item.Image" /><td>
<td>#item.ProductId</td>
<td>#item.HotelName</td>
<td>#item.HotelPrice</td>
</tr>
}

Related

How to bind data using custom form controller to view in mvc4

mycontroller.cs
[HttpPost]
public ActionResult Index(int searchtext)
{
var data = (from pm in db.ProductMasters
join shi in db.SuppliersHotelsInfoes
on pm.ProductID equals shi.LocHotelID
where shi.SearchID == searchtext
select pm).ToList().Take(10);
ViewBag.Data = data;
return View();
}
am sending viewBag.Data to view
<% try { %>
<tr><td>
<% foreach(var item in ViewBag.Data){ %>
<img alt="" src="<%item. %>" />
</td><%} %> <% foreach(var item in ViewBag.Data) { %>
<td><%: Html.DisplayFor(modelItem => "")%></td>
<td><%: Html.DisplayFor(modelItem => "")%> </td>
<td><%: Html.DisplayFor(modelItem => "")%></td>
</tr>
<%} }%>
<%catch(Exception ex){ }%>
</table>
Here, how can we take the values from "var item"
I haven't used aspx view syntax for a while but I believe you are missing the equals sign.
You currently have this:
<img alt="" src="<%item. %>" />
instead it should be this
<img alt="" src="<%=item. %>" />
Notice the = before "item"
Take a look here for more info http://weblogs.asp.net/scottgu/archive/2010/04/06/new-lt-gt-syntax-for-html-encoding-output-in-asp-net-4-and-asp-net-mvc-2.aspx
Also consider using a later version of MVC which supports razor syntax which is much cleaner.
Edit:
After your comment I see your issue. You are using the ViewBag which is a dynamic type. Therefore it cannot infer that your ViewBag.Data object is a collection of product masters. You have two options:
Option 1 - Don't use the ViewBag, instead use a strongly typed model.
Option 2 - In your view cast your ViewBag.Data to the List of Product Masters.
For example:
Instead of
<% foreach(var item in ViewBag.Data){ %>
Use this
<% foreach(var item in (List<ProductMaster>)ViewBag.Data){ %>

How to get confirmed list (IEnumerable) in HttpPost method?

in my ASP .Net MVC 2 application the user is shown a list of items and must click confirm before the list is persisted to the database.
When the user clicks confirm, in the HttpPost method the parameter is null. Everything works until the HttpPost method is called. At this point the list that must be persisted is null.
How do I get the confirmed values ?
I've tried using TempData in the HttpGet method but TempData is also null in the HttpPost method.
Here is the controller code.
public ActionResult Confirm()
{
List<ConfirmVehicleModel> vehicles = GetAllVehicles();
return View(vehicles);
}
[HttpPost]
public ActionResult Confirm(List<ConfirmVehicleModel> model)
{
//model is null, why ?
UploadVehiclesModelService service = new Models.UploadVehiclesModelService();
service.StoreVehicles(model, User.Identity.Name);
return RedirectToAction("Index", "UploadVehicles");
}
And here is the Confirm view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<RM.Application.Models.ConfirmVehicleModel>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Confirm
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>
Confirm that the vehicles below should be added.</h2>
<table>
<tr>
<th>
ReferenceType
</th>
<th>
ReferenceName
</th>
</tr>
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%= Html.Encode(item.ReferenceType) %>
</td>
<td>
<%= Html.Encode(item.ReferenceName) %>
</td>
</tr>
<% } %>
</table>
<div>
<% using (Html.BeginForm())
{ %>
<input type="submit" value="Confirm" />
|
<%= Html.ActionLink("Back to upload form", "Index") %>
<% } %>
</div>
</asp:Content>
Thanks for any help,
Kind regards
Bob
Your HTML.BeginForm() is out of place it should surround the values you wish to pass.
Try:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Confirm that the vehicles below should be added.</h2>
<% using (Html.BeginForm())
{ %>
<table>
<tr>
<th>
ReferenceType
</th>
<th>
ReferenceName
</th>
</tr>
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%= Html.Encode(item.ReferenceType) %>
<%= Html.HiddenFor(model => item.ReferenceType)%>
</td>
<td>
<%= Html.Encode(item.ReferenceName) %>
<%= Html.HiddenFor(model => item.ReferenceName)%>
</td>
</tr>
<% } %>
</table>
<div>
<input type="submit" value="Confirm" />
|
<%= Html.ActionLink("Back to upload form", "Index") %>
<% } %>
</div>
Nicholas advice helped. I replaced the foreach loop with a for loop and used Html.HiddenFor.
<% for (int i = 0; i < Model.Count(); i++)
{ %>
<%= Html.HiddenFor(model=>model[i].ReferenceType) %>
<%= Html.HiddenFor(model=>model[i].ReferenceName) %>
<tr>
<td>
<%= Html.Encode(Model[i].ReferenceType) %>
</td>
<td>
<%= Html.Encode(Model[i].ReferenceName) %>
</td>
</tr>
<% } %>
I also changed the top line of the the view to (previously IEnumerable, now List).
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<List<RM.Application.Models.ConfirmVehicleModel>>" %>\\
The List<ConfirmVehicleModel> model parameter of the HttpPost method is now populated.

Update complex model in ASP.NET MVC 2?

How can I update a complex model? I have the following View:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Tidrapportering.Models.Week>" %>
<% using (Html.BeginForm())
{%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<table width="100%">
<% foreach (var task in Model.Tasks)
{ %>
<tr>
<td>
<%: task.Customer.CustomerName %>
</td>
<td>
<%: task.TaskName %>
</td>
<td>
<% foreach (var ts in task.TimeSegments)
{ %>
<%= Html.TextBox("Hours", ts.Hours)%>
<% } %>
</td>
</tr>
<% } %>
</table>
<p>
<input type="submit" value="Spara tid" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
And I tried update it as usual just calling UpdataModel on the model object: UpdateModel(week); But that didn't work. So I read something about having to update each property separately in complex models, and tried to adapt it to my situation. Here's my attempt in the Controller:
[HttpPost]
public ActionResult EditTasks(int id, FormCollection collection)
{
//try
//{
Week week = _model.GetWeek(id);
foreach (var task in week.Tasks)
{
foreach (var timeSegment in task.TimeSegments)
{
UpdateModel(timeSegment.Hours, "Hours");
}
}
//UpdateModel(week);
_model.Save();
return RedirectToAction("Index");
//}
//catch
//{
// return View();
//}
}
But that didn't work either. It seems to work if the property is a string, but this is an int, and the compiler complains that it must be a reference type to be used as a TModel.
I don't know if this is the way to go, I just need to understand how to be able to update a complex type model like this. This can't be too uncommon so there must be some standard method, but I can't figure it out...
Any ideas?
UPDATE:
The following works:
Action method:
[HttpPost]
public ActionResult EditTasks(int id, FormCollection collection)
{
try
{
Week week = _model.GetWeek(id);
for (int i = 0; i < week.TaskList.Count; i++)
{
var task = week.TaskList[i];
for (int j = 0; j < task.TimeSegmentList.Count; j++)
{
int hours = Int32.Parse(collection["TaskList[" + i + "].TimeSegmentList[" + j + "].Hours"]);
week.TaskList[i].TimeSegmentList[j].Hours = hours;
}
}
//UpdateModel(week);
_model.Save();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
View:
<% for (int i = 0; i < Model.TaskList.Count; i++)
{
var task = Model.TaskList[i];
%>
<tr>
<td>
<%: task.Customer.CustomerName %>
</td>
<td>
<%: task.TaskName %>
</td>
<% for (int j = 0; j < task.TimeSegmentList.Count; j++)
{ %>
<td>
<%: Html.TextBoxFor(model => model.TaskList[i].TimeSegmentList[j].Hours, new { #class = "hourInput" })%>
</td>
<% } %>
</tr>
<% } %>
However, the updating has to be manual like this, which seems unnecessarily complex. I found a post by Phil Haack (http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx) which seems to suggest this should be possible to do in a simpler way, like this:
[HttpPost]
public ActionResult EditTasks(Week week)
{
try
{
UpdateModel(week);
_model.Save();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I.e. simply receiving the Week as the parameter for the method (in Haacks example it doesn't even seem he has to call UpdateModel, just having the View bound to the objects seems to be enough, so I would only have to save it in the database... But it doesn't work for me. The Week object that is returned doesn't seem to be the same one sent to the view, it has no items in its collections of tasks, e.g.
So why doesn't this work?
Try with for instead of foreach
<fieldset>
<legend>Fields</legend>
<table width="100%">
<% for (int i = 0; i < Model.Tasks.Count; i++)
{
var task = Model.Tasks[i];
%>
<tr>
<td>
<%: task.Customer.CustomerName %>
</td>
<td>
<%: task.TaskName %>
</td>
<td>
<% for (int j = 0; j < task.TimeSegments.Count; j++)
{ %>
<%= Html.TextBox("Model.Tasks["+i+"].TimeSegments["+j+"].Hours")%>
<% } %>
</td>
</tr>
<% } %>
</table>
<p>
<input type="submit" value="Spara tid" />
</p>
</fieldset>

ASP.NET MVC: How to call javascript function in Html.ActionLink

When I edit single recored in page, I use checkbox to get a selected row not every row with an actionlink element, but it seemed I cant make this way happen through calling javascript code (function GetSelectedRow() should return an id). Could anyone have a nice idea?
<head runat="server">
<title>Index</title>
<script type="text/javascript" language="javascript">
function GetSelectedRow() {
var a = 0;
var chkBoxes = document.getElementsByName("chkSelect");
var count = chkBoxes.length;
for (var i = 0; i < count; i++) {
if (chkBoxes[i].checked == true)
a = chkBoxes[i].primaryKeyID;
}
return a;
}
</script>
</head>
<body>
<div>
<span style="width:20%">
<%: Html.ActionLink("Add", "Create")%>
</span>
<span>
<%: Html.ActionLink("Edit", "Edit", new { id = GetSelectedRow()) %>
</span>
<span>
<%: Html.ActionLink("Detial", "Details", new { id = GetSelectedRow() })%>
</span>
<span>
<%: Html.ActionLink("Delete", "Delete", new { id = GetSelectedRow()) %>
</span>
</div>
<table>
<tr>
<th></th>
<th>
CategoryID
</th>
<th>
CategoryName
</th>
<th>
Description
</th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td>
<%: Html.ActionLink("Details", "Details", new { id = item.AppCategoryID })%>
</td>
<td>
<%: Html.CheckBox("chkSelect", false, new { primaryKeyID = item.AppCategoryID })%>
</td>
<td>
<%: item.AppCategoryID %>
</td>
<td>
<%: item.AppCategoryName %>
</td>
<td>
<%: item.Description %>
</td>
</tr>
<% } %>
</table>
</body>
You could do something like this:
<script type="text/javascript">
function RedirectUsingSelectedRow() {
var id = GetSelectedRow();
window.location = '../Controller/Details/' + id;
}
</script>
Edit
Mixing server and client that way won't work. What you need to do, when a row is selected, is to manipulate the URL. So rather than return a URL, have GetSelectedRow do:
function GetSelectedRow() {
//existing logic minus return
var link1 = document.getElementById("Link1"); //this would require giving links an ID
link1.href = '<%= Url.Action("Detail", new { controller = "Details" }) %>' +
'id=' a.toString();
}
You have to change it from client-side javascript is the key, rather than doing that during the rendering process.
HTH.
Try this -
$('#GetSelectedRow').click(function() { /* Your Code */ });
Calling java script function by id 'GetSelectedRow'. Instead of calling the function by id, you can directly call the function
<% Html.ActionLink("Edit", "Edit", "Controller", new { onclick = "GetSelectedRow();"}) %>

ASP.NET MVC 2 - Saving child entities on form submit

I'm using ASP.NET MVC 2 and am struggling with saving child entities. I have an existing Invoice entity (which I create on a separate form) and then I have a LogHours view that I'd like to use to save InvoiceLog's, which are child entities of Invoice. Here's the view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<TothSolutions.Data.Invoice>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Log Hours
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="HeadContent" runat="server">
<script type="text/javascript">
$(document).ready(function () {
$("#InvoiceLogs_0__Description").focus();
});
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Log Hours</h2>
<% using (Html.BeginForm("SaveHours", "Invoices")) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<table>
<tr>
<th>Date</th>
<th>Description</th>
<th>Hours</th>
</tr>
<%
int index = 0;
foreach (var log in Model.InvoiceLogs) {
%>
<tr>
<td><%: log.LogDate.ToShortDateString() %></td>
<td><%: Html.TextBox("InvoiceLogs[" + index + "].Description")%></td>
<td><%: Html.TextBox("InvoiceLogs[" + index + "].Hours")%></td>
<td>Hours</td>
</tr>
<%
index++;
}
%>
</table>
<p>
<%: Html.Hidden("InvoiceID") %>
<%: Html.Hidden("CreateDate") %>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
And here's the controller code:
//GET: /Secure/Invoices/LogHours/
public ActionResult LogHours(int id)
{
var invoice = DataContext.InvoiceData.Get(id);
if (invoice == null)
{
throw new Exception("Invoice not found with id: " + id);
}
return View(invoice);
}
//POST: /Secure/Invoices/SaveHours/
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveHours([Bind(Exclude = "InvoiceLogs")]Invoice invoice)
{
TryUpdateModel(invoice.InvoiceLogs, "InvoiceLogs");
invoice.UpdateDate = DateTime.Now;
invoice.DeveloperID = DeveloperID;
//attaching existing invoice.
DataContext.InvoiceData.Attach(invoice);
//save changes.
DataContext.SaveChanges();
//redirect to invoice list.
return RedirectToAction("Index");
}
And the data access code:
public static void Attach(Invoice invoice)
{
var i = new Invoice { InvoiceID = invoice.InvoiceID };
db.Invoices.Attach(i);
db.Invoices.ApplyCurrentValues(invoice);
}
In the SaveHours action, it properly sets the values of the InvoiceLog entities after I call TryUpdateModel but when it does SaveChanges it doesn't update the database with the new values. Also, if you manually update the values of the InvoiceLog entries in the database and then go to this page it doesn't populate the textboxes so it's clearly not binding correctly.
Thanks,
Justin
Got it working, I needed to populate the InvoiceLogID and InvoiceID in hidden fields so they'd get populated in the EntityCollection.

Resources