Return different model on partial view - c#

I'm having some trouble returning a ViewBag with a list of a model to a PartialView, which is a different type of model from the ParentView, but I wish to render the result, only inside the partial view that is rendered on the Parent View. Perhaps looking at my code, will give a better understanding.
Here is my controller:
public ActionResult Search()
{
//ViewBag.Usuarios = db.User.ToList();
return View();
}
[HttpGet]
public ActionResult Pesquisar(UserFilter userFilter)
{
List<UserModel> retorno = new List<UserModel>();
ViewBag.Mensagem = "Não foi encontrado registro com os filtros informados";
if (userFilter.Name != null)
{
retorno = db.User.Where(x => x.Name.Contains(userFilter.Name)).ToList();
if (retorno != null)
{
ViewBag.Usuarios = retorno;
return PartialView("Search", ViewBag.Usuarios);
}
return View("Search", ViewBag.Mensagem);
}
if (userFilter.UserID != 0)
{
UserModel retorn = new UserModel();
var id = Convert.ToInt16(userFilter.UserID);
retorn = db.User.FirstOrDefault(x => x.UserID == id);
return View("Details", retorn);
}
return View("Search", ViewBag.Mensagem);
}
Here is my Parent View
#model Sistema_ADFP.Filters.UserFilter
<body>
<div class="container">
<h2>Buscar Usuário</h2>
<form role="form" method="GET" action="/User/Pesquisar">
<div class="col-lg-12">
<div class="col-lg-3">
<div class="form-group">
<label>Nome</label>
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
<label>ID</label>
#Html.EditorFor(model => model.UserID, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="col-lg-3">
<div class="form-group">
<label>CPF</label>
#Html.EditorFor(model => model.CPF, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
</div>
<div class="clearfix"></div>
<div class="form-group pull-right">
<label> </label>
<input type="submit" class="btn btn-primary"/>
</div>
</form>
</div>
<div class="clearfix"></div>
#{
if (ViewBag.Mensagem == null)
{
<div id="resultadoLista">
#{
Html.RenderPartial("_List");
}
</div>
}
else
{
<label>Nenhum registro encontrado</label>
}
}
</body>
And here is my Partial View
<h4>Usuários</h4>
<div class="table-responsive">
<table class="table">
<tr class="inverse" align="center">
<th>Nome</th>
<th>Sexo</th>
<th>Estado Civil</th>
<th>Educação</th>
<th>Profissão</th>
<th>Voluntário</th>
<th>Data Nascimento</th>
<th>Ações</th>
</tr>
#if (ViewBag.Usuarios != null)
{
foreach (var item in ViewBag.Usuarios)
{
<tr class="active">
<td data-th="Nome"><a class="modal-ajax-link" href="#test-popup">#item.Name</a></td>
<td data-th="Sexo">#item.Sex</td>
<td data-th="EstadoCivil">#item.MaritalStatus</td>
<td data-th="Education" align="center">#item.Education.Description</td>
<td data-th="Education" align="center">#item.Profession.Name</td>
#if (item.Voluntary)
{
<td data-th="Voluntario" align="center">Ativo</td>
}
else
{
<td data-th="Voluntario" align="center">Inativo</td>
}
<td data-th="DataNasc" align="center">#item.BirthDate</td>
#* data-mfp-src="#HttpContext.Current.Request.Url.Host:#HttpContext.Current.Request.Url.Port/User/Details/2" *#
<td data-th="Ações" align="center">
<a class="btn btn-info modal-ajax-link" href='#Html.ActionLink("Editar", "Edit",
new { id = #item.UserID })'><i class="icon_pencil"></i></a>
<a class="btn btn-danger modal-ajax-link" href="#delete-modal"><i class="icon_trash_alt"></i></a>
</td>
</tr>
}
}
</table>
</div>
The error that i'm getting is:
The model item passed into the dictionary is of type
'System.Collections.Generic.List`1[Sistema_ADFP.Models.UserModel]',
but this dictionary requires a model item of type
'Sistema_ADFP.Filters.UserFilter'.
I understand the error reason , but I can not get to a means of resetting the flow and make it work. Does anybody knows or have a tip of what i can do ?

The solution to fix this is by not using ViewBag and create ViewModel for your view. The ViewModel is a class for your view and will have all necessary properties for your view. So, for the sake of example, you could have a view model called:
public class WrapperVM
{
public UserFilter Filter {get; set;}
public UserModel Model {get; set;}
}
Thus, fill these properties and pass WrapperVM to parent view (change to #model WrapperVM) and then you can pass usermodel to partial view. I hope this helps.

Related

How can I view both table and form in same view

I have recently learning ASP.NET MVC5.
I am trying to see both the form and a table(return as partialview) in one view but i'm getting this error.
System.NullReferenceException: Object reference does not set to an instance of an object.
Here is my Model:
public class Prescription
{
[Key]
public int PrescriptionID { get; set; }
[ForeignKey("Assessment")]
public int? AssessmentID { get; set; }
public Assessment Assessment { get; set; }
[ForeignKey("Medicine")]
[Display(Name ="Prescription")]
public int? MedcineID { get; set; }
public Medicine Medicine { get; set; }
}
My main view where I want to put my partial view:
#using ClinicManagemet
#model ClinicManagemet.Models.Prescription
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Prescription</h4>
<hr />
<div class="form-group">
#Html.LabelFor(model => model.MedcineID, "MedcineID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("MedcineID", null, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.MedcineID, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
#Html.Action("ViewPrescription","Assessments")
<div>
#Html.ActionLink("Back to Home", "Home")
</div>
My partial view:
#model IEnumerable<ClinicManagemet.Models.Prescription>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Assessment.Complaint)
</th>
<th>
#Html.DisplayNameFor(model => model.Medicine.MedicineName)
</th>
<th></th>
</tr>
#foreach (var item in Model) { //Here is the line where I get the error
<tr>
<td>
#Html.DisplayFor(modelItem => item.Assessment.Complaint)
</td>
<td>
#Html.DisplayFor(modelItem => item.Medicine.MedicineName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.PrescriptionID }) |
#Html.ActionLink("Details", "Details", new { id=item.PrescriptionID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.PrescriptionID })
</td>
</tr>
}
</table>
My partial view's controller:
public ActionResult ViewPrescription()
{
return PartialView();
}
Edit: If I fix this, I'll try to add Ajax so whenever I insert something, it will just refresh the partial view.
Load your partial view like this,
#{
Html.RenderAction("ViewPrescription","YourControllerName")
}
And in your ViewPrescription method, return the data,
{
//Fetch the data here
return PartialView(model);
}
Hope it helps.
You're not passing a model into the partial view when returning the view.
public ActionResult ViewPrescription()
{
ClinicManagemet.Models.Prescription model = _service.GetPerscription();
return PartialView(model);
}

MVC Passing a Complex Object to the controller for saving

I am writing a web page with MVC and Entity Framework.
I have an order with line items attached and want to return a complex object to the controller for processing.
I have now included all the code.
My view:
#model BCMManci.ViewModels.OrderCreateGroup
#{
ViewBag.Title = "Create";
}
<h2>New Order</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<h4>#Html.DisplayFor(model => model.Order.Customer.FullName)</h4>
<table>
<tr>
<td><b>Order Date:</b> #Html.DisplayFor(model => model.Order.OrderDate)</td>
<td><b>Status:</b> #Html.DisplayFor(model => model.Order.OrderStatus.OrderStatusName)</td>
</tr>
<tr>
<td colspan="2">
<b>Notes</b>
#Html.EditorFor(model => model.Order.Notes, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
</table>
#Html.ValidationMessageFor(model => model.Order.Notes, "", new { #class = "text-danger" })
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<table class="table table-striped table-hover">
<thead>
<tr>
<td>Name</td>
<td>Price</td>
<td>Discount</td>
<td>Total</td>
<td>Quantity</td>
</tr>
</thead>
<tbody>
#foreach (var product in Model.ProductWithPrices)
{
<tr>
<td>
#Html.DisplayFor(modelItem => product.ProductName)
</td>
<td>
#Html.DisplayFor(modelItem => product.SellingPrice)
</td>
<td>
#Html.DisplayFor(modelItem => product.DiscountPrice)
</td>
<td>
#Html.DisplayFor(modelItem => product.TotalPrice)
</td>
<td>
#Html.EditorFor(modelItem => product.Quantity, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</tbody>
</table>
<input type="submit" value="Create" class="btn btn-default" />
}
<div class="btn btn-danger">
#Html.ActionLink("Cancel", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Order,ProductWithPrices,Order.Note,product.Quantity")] OrderCreateGroup order)
{
try
{
if (ModelState.IsValid)
{
db.Orders.Add(order.Order);
foreach (var orderItem in order.ProductWithPrices.Select(item => new OrderItem
{
OrderId = order.Order.OrderId,
ProductId = item.ProductId,
Quantity = item.Quantity,
ItemPrice = item.SellingPrice,
ItemDiscount = item.DiscountPrice,
ItemTotal = item.TotalPrice
}))
{
db.OrderItems.Add(orderItem);
}
db.SaveChanges();
return RedirectToAction("ConfirmOrder", new {id = order.Order.OrderId});
}
}
catch (DataException /* dex */)
{
//TODO: Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
ViewBag.Products = db.Products.Where(model => model.IsActive == true);
PopulateDropdownLists();
return View(order);
}
Data Source:
public class OrderCreateGroup
{
public OrderCreateGroup()
{
ProductWithPrices = new List<ProductWithPrice>();
}
public Order Order { get; set; }
public ICollection<ProductWithPrice> ProductWithPrices { get; set; }
}
public class ProductWithPrice : Product
{
public decimal SellingPrice { get; set; }
public decimal DiscountPrice { get; set; }
public int Quantity { get; set; }
public decimal TotalPrice { get; set; }
}
However, the values that are entered on the form are not being passed, through. So I can't access them in the controller. The 'productWithPrices' collection is null although there is Data in it on the web page.
I have tried making it asyc and also tried changing the ActionLink button like below but it didn't get to the controller.
#Html.ActionLink("Create", "Create", "Orders", new { orderCreateGoup = Model }, null)
This is the controller but it now doesn't make sense as the parameter passed in the datasource for the page.
public ActionResult Create(OrderCreateGroup orderCreateGoup)
Please, can you give me direction on the best way of doing this?
In your OrderCreateGroup class initialize the collection to an empty list.
public class OrderCreateGroup
{
public OrderCreateGroup()
{
ProductWithPrices = new List<ProductWithPrice>();
}
public Order Order { get; set; }
public ICollection<ProductWithPrice> ProductWithPrices { get; set; }
}
You'll need to add #Html.HiddenFor(m => m.SellingPrice) and similarly for other bound fields that are using DisplayFor if you want to post them back to the controller.
Note: For your benefit, try to have a look at the generated HTML code when your page is rendered in the browser and see what tags are generated inside the <form> tag with a name attribute.
make sure you bind the appropriate property from the complex object, like the following:
#model BCMManci.ViewModels.OrderCreateGroup
...
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
...
<div class="form-group">
#Html.LabelFor(model => model.LastName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.OrderCreateGroup.Order.Quantity, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.OrderCreateGroup.Order.Quantity, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Note:model.OrderCreateGroup.Order.Quantity would be one the your order's property.
hope this helps.

MVC Update view with uploaded file

I'm new to MVC and have spent several hours trying to find a solution to this issue. I'm trying to set up an invoicing system for some rental properties. The property manger provides an excel file that contains the current water readings. I have to subtract the water readings from last months to find out the monthly usage. The view I've made does this and shows all the units simultaneously. What I'm having problems with is passing the uploaded file along with the model data (last months readings) to the controller. The file shows up but none of the other data.
In the view I have two submit buttons. One to upload the file to be integrated into the model data and the other to create the new records based on the previous and current(uploaded) data. Below are the relevant model, view and controllers.
Ultimately the billing manger would see last month's data, upload the new data, review and verify there are no errors and then submit the data for the new invoices.
If there is better way to accomplish that then what I'm trying here please let me know. This just seemed like it would be easier that recreating model data with all the linq queries. Thanks in advance for your help!
Model:
public partial class UtilityData
{
public DateTime bEntryDate { get; set; }
public string bPrevDate { get; set; }
public int bID { get; set; }
//public int residenceCount { get; set; }
public IEnumerable<UtilEntry> utilData { get; set; }
public HttpPostedFileBase UploadFile { get; set; }
}
public partial class UtilEntry
{
public int rID { get; set; }
public long? WaterReading { get; set; }
public int ResNumber { get; set; }
public long? prevWaterReading { get; set; }
public decimal wDifference { get; set; }
public int GrnUpper { get; set; }
public int GrnLower { get; set; }
public int YelUpper { get; set; }
public int YelLower { get; set; }
}
View:
#model PropertiesAdminSite.Models.UtilityData
#{
ViewBag.Title = "CreateNewCycle";
}
<h2>New Residence Utilities</h2>
#using (Html.BeginForm("Upload", "ImportWater", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="control-group">
#Html.TextBoxFor(m => m.UploadFile, new { type = "file"})
#*<input type="file" class="btn btn-info" name="postedFile"/>*#
</div>
<div class="control-group">
<input type="submit" class="btn btn-info" value="Upload" />
</div>
<div class="col-lg-12 visible-lg">
<br>
<span style="color:green">#ViewBag.Message</span>
</div>
}
#using (Html.BeginForm("IndexMulti", "Utilities", FormMethod.Post))
{
#Html.AntiForgeryToken()
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading">
#Html.LabelFor(model => model.bEntryDate, htmlAttributes: new { #class = "control-label col-md-1" })
#Html.DisplayFor(model => model.bEntryDate)
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="dataTable_wrapper">
<!--div id="dataTables-example_wrapper" class="dataTables_wrapper form-inline dt-bootstrap no-footer">-->
<div class="row">
<div class="col-sm-12">
<table class="table table-striped table-bordered table-hover dataTable no-footer" id="dataTables-Bills" role="grid" aria-describedby="dataTables-example_info">
<!-- /table headers-->
<thead>
<tr role="row">
<th>#Html.DisplayNameFor(model => model.utilData.First().ResNumber)</th>
<th>#Html.DisplayNameFor(model => model.utilData.First().WaterReading)</th>
<th>
#Html.DisplayNameFor(model => model.utilData.First().prevWaterReading)
#* TODO: fix date format *#
#Html.DisplayFor(model => model.bPrevDate)
</th>
<th>#Html.DisplayNameFor(model => model.utilData.First().wDifference)</th>
<th>Actions</th>
</tr>
</thead>
<!-- /table body-->
<tbody>
#foreach (var item in Model.utilData)
{
<tr role="row">
<td>
#Html.DisplayFor(modelItem => item.ResNumber, null, "residence_" + item.rID)
#Html.HiddenFor(model => item.GrnLower, new { id = "grnLower_" + item.rID })
#Html.HiddenFor(model => item.GrnUpper, new { id = "grnUpper_" + item.rID })
#Html.HiddenFor(model => item.YelLower, new { id = "yelLower_" + item.rID })
#Html.HiddenFor(model => item.YelUpper, new { id = "yelUpper_" + item.rID })
</td>
<td>
#Html.EditorFor(model => item.WaterReading, null, "waterReading_" + item.rID)
</td>
<td>
<span id="#string.Format("prevWater_{0}",item.rID)">
#Html.DisplayFor(model => item.prevWaterReading, null, "prevWater_" + item.rID)
</span>
#Html.HiddenFor(model => item.prevWaterReading, new { id = "hprevWater_" + item.rID })
</td>
<td>
<span id="#string.Format("hdifference_{0}",item.rID)">
#Html.DisplayFor(model => item.wDifference)
</span>
#Html.HiddenFor(model => item.prevWaterReading, new { id = "hdifference_" + item.rID })
</td>
<td>
#Html.ActionLink("View History", "ExportDataIndex", "ExportData", new { rID = item.rID, bId = Model.bID }, null) |
<a href="#Url.Action("ExportToExcel", "ExportData", new { rID = item.rID, bId = Model.bID })" class="btn btn-success">
<i class="fa fa-file-excel-o" aria-hidden="true" title="Export to Excel"></i>
</a> |
<a href="#Url.Action("ChartData", "Utilities", new { rID = item.rID, bId = Model.bID })" class="btn btn-info">
<i class="fa fa-bar-chart" aria-hidden="true" title="Water Usage History"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
Controller:
// GET: ImportWater
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload([Bind(Include = "bEntryDate,bPrevDate,bID,utilData,UploadFile")]UtilityData uData) //<----The file gets uploaded but none of the Model data from the view.
{
HttpPostedFileBase postedFile = uData.UploadFile;
if (postedFile != null && postedFile.ContentLength > 0)
{
string fileName = postedFile.FileName;
string fileContentType = postedFile.ContentType;
byte[] fileBytes = new byte[postedFile.ContentLength];
var data = postedFile.InputStream.Read(fileBytes, 0, Convert.ToInt32(postedFile.ContentLength));
using (var package = new ExcelPackage(postedFile.InputStream))
{
//Todo: read file and insert data
}
ViewBag.Message = "File uploaded successfully.";
}
return View(uData);
}
I now understand what the issue was; I didn't fully understand how the POST worked. I thought the form would always send the full model object back and that is not the case. I created hidden items to capturethe model data I wanted to post back.
#using (Html.BeginForm("Upload", "ImportWater", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="control-group">
#Html.TextBoxFor(m => m.UploadFile, new { type = "file"})
#*<input type="file" class="btn btn-info" name="postedFile"/>*#
</div>
<div class="control-group">
<input type="submit" class="btn btn-info" value="Upload" />
</div>
<div class="col-lg-12 visible-lg">
<br>
<span style="color:green">#ViewBag.Message</span>
#Html.HiddenFor(model => model.bID)
#Html.HiddenFor(model => model.bEntryDate)
#Html.HiddenFor(model => model.bPrevDate)
#for (int i = 0; i < Model.utilData.Count(); i++)
{
#Html.HiddenFor(model => model.utilData[i].ResNumber)
#Html.HiddenFor(model => model.utilData[i].GrnLower)
#Html.HiddenFor(model => model.utilData[i].GrnUpper)
#Html.HiddenFor(model => model.utilData[i].prevWaterReading)
#Html.HiddenFor(model => model.utilData[i].rID)
#Html.HiddenFor(model => model.utilData[i].WaterReading)
#Html.HiddenFor(model => model.utilData[i].wDifference)
#Html.HiddenFor(model => model.utilData[i].YelLower)
#Html.HiddenFor(model => model.utilData[i].YelUpper)
}
</div>
}

How to implement Index and create in the same page on MVC 5?

I am a beginner on MVC and I am trying to Create a web app where I want the user to be able to create new items and view them in the same page.
I am trying to do this by using partial view for the Create Action inside the Index view.
The problem is I am not able to redirect from the child to the Index to update the list after creating new item. And I'm getting this error(Child actions are not allowed to perform redirect actions.)
Here is my model
public class Expense
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
[DataType(DataType.Currency)]
public decimal Amount { get; set; }
//[Required]
public string ApplicationUserId { get; set; }
}
,here are my Index and Create Actions
public ActionResult Index()
{
return View(db.Expenses.ToList());
}
public ActionResult Create()
{
return PartialView("Create", new Expense());
//return View();
}
// POST: /Expense/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include="Id,Title,Amount,ApplicationUserId")] Expense expense)
{
if (ModelState.IsValid)
{
expense.ApplicationUserId = User.Identity.GetUserId();
db.Expenses.Add(expense);
db.SaveChanges();
return RedirectToAction("Index"); // Here is where The exception is thrown
}
return View();
}
And here is my Index view
#model IEnumerable<HomeManager.Models.Expense>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Amount)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Amount)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
<p>
#Html.ActionLink("Create New", "Create")
#{Html.RenderAction("Create", "Expense");}
</p>
And here is my Create view
#model HomeManager.Models.Expense
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Expense</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Title, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Title)
#Html.ValidationMessageFor(model => model.Title)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Amount, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Amount)
#Html.ValidationMessageFor(model => model.Amount)
</div>
</div>
#*<div class="form-group">
#Html.LabelFor(model => model.ApplicationUserId, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ApplicationUserId)
#Html.ValidationMessageFor(model => model.ApplicationUserId)
</div>
</div>*#
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default"/>
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The error is occurring because you html for the form is generating
<form action="/Expense/Index" method="post">
not action="/Expense/Create" as it needs to be. If you put a breakpoint on both the Index() GET and Create(Expense expense) POST methods, you will see that your hitting both of them when you submit the form.
To solve this, explicitly set the action and controller names in the BeginForm() method of the partial view
#using (Html.BeginForm("Create", "Expense"))
Note that since your Create() GET method is not performing any logic, you can also use
#{ Html.RenderPartial("Create", new Expense()); }
in lieu of RenderAction
If you are trying to display the new records immediately they are created then I suggest you use a Javascript library like Knockout, Angular Js or Ember.
Alternatively if you want to use only MVC then you will need to make an ajax call to a method that returns a partial view of the updated Expense record and place this partial view in your DOM in your view.

ASP.NET MVC4 IEnumerable empty on post

I have read several answers on this issue but despite this, it would appear I have developed code blindness.
I have the following view model:
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual IEnumerable<ProductSimpleResponse> ProductSimpleResponse { get; set; }
}
This is then passed into a view and then a partial view:
#model Websites.ViewModels.IndividualProductVm #{ ViewBag.Title = "Edit"; }
<h2>Edit</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { name = "form", id = "mainForm" })) { #Html.AntiForgeryToken() #Html.ValidationSummary(true, "", new { #class = "text-danger" }) #Html.HiddenFor(model => model.Products.Id) #Html.HiddenFor(model
=> model.ProductSummary.SupplierId) Html.RenderPartial("_IndividualProduct", Model);
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index", new { id = Model.ProductSummary.SupplierId }, new { #class = "btn btn-default" })
</div>
#section Scripts { #Scripts.Render("~/bundles/jqueryval") }
#model Websites.ViewModels.IndividualProductVm
<div>
#Html.LabelFor(model => model.Products.ProductCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div style="clear:both;"></div>
<div>
#Html.LabelFor(model => model.Products.ProductDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductDescription, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<table class="table">
<tr>
<th>
Present
</th>
</tr>
#foreach (var item in Model.ProductSimpleResponse)
{
<tr>
#Html.HiddenFor(modelItem => item.Id)
#Html.HiddenFor(modelItem => item.SupplierId)
#Html.HiddenFor(modelItem => item.ProductCode)
<td>
#Html.EditorFor(modelItem => item.Present)
</td>
</tr>
}
</table>
However, when I enter the edit post, my viewmodel is null for the IEnumerable<ProductSimpleResponse> but fine for the other two classes.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IndividualProductVm model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index", new { id = model.ProductSummary.SupplierId });
}
return View(model.Products);
}
If someone can explain what I'm doing wrong, I'd be most grateful.
Your property name is ProductSimpleResponse, alhtough the type is ProductSvhcSimpleResponse, so to iterate through it you should have.
#foreach (var item in Model.ProductSimpleResponse)
NOT
#foreach (var item in Model.ProductSvhcSimpleResponse)
use List because
IEnumerable is suitable just for iterate through collection and you can not modify (Add or Remove) data IEnumerable bring ALL data from server to client then filter them, assume that you have a lot of records so IEnumerable puts overhead on your memory.
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual List<ProductSvhcSimpleResponse> ProductSimpleResponse { get; set; }
}
More help click here

Categories

Resources