I am new to ASP.NET MVC. I have a parent view and a partial view, both using different models. My concern is when I submit the page, the partial view data also should pass to the parent view HTTP Post method. I had created a property in the parent view model to get the data from the partial view model. But when I submit the page, I am getting null. any help would be appreciated
Parent view caseDetails.cshtml:
#model EMSD.Module.Case.CPN.Model.CPNDetailViewModel
#{
ViewBag.Title = "_CPNCaseDetail";
}
<table class="table table-striped">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<tr>
<td class="leftheaderform">
#Html.LabelFor(model => model.CPN_CAT)
<span style="color:red">*</span>
</td>
<td class="rightdetailform" colspan="3">
#Html.DropDownListFor(model => model.CPN_CAT, new SelectList(Model.InformedCat, "ID", "Name"), "--Select--", new { #class = "form-control form-control-sm col-3" })
#Html.ValidationMessageFor(model => model.CPN_CAT, "", new { #class = "text-danger" })
</td>
</tr>
<tr>
<td class="leftheaderform">
#Html.LabelFor(model => model.CPN_CAT_RMK)
</td>
<td class="rightdetailform" colspan="3">
#Html.TextAreaFor(model => model.CPN_CAT_RMK, new { htmlAttributes = new { #class = "form-control form-control-sm" }, rows = 2, style = "width: 100%; max-width: 100%;" })
#Html.ValidationMessageFor(model => model.CPN_CAT_RMK, "", new { #class = "text-danger" })
</td>
</tr>
*used HTML.partial for calling partial view*
#Html.Partial("~/Views/Shared/Address.cshtml", Model.Address)
</table>
Parent view model:
public class CPNDetailViewModel
{
[DisplayName("Informed Category")]
public string CPN_CAT { get; set; }
[DisplayName("Remarks ")]
public string CPN_CAT_RMK { get; set; }
// property for getting data from partial view
public UpdateGasSupplierViewModel Address { get; set; }
}
Partial view Address.chtml:
#model EMSD.Module.Misc.Model.UpdateGasSupplierViewModel
<table class="table table-striped">
<tr>
<td><font color="blue">Search Address</font></td>
<td colspan="4"> <input id="FreeEnglishAddressText" class="form-control" /></td>
<td><button type="button" onclick="callAPI()" class="btn btn-outline-primary form-control">Search</button></td>
</tr>
<tr>
<td>
Flat
</td>
<td>
#Html.DropDownListFor(model => model.GSC_ENG_FT, new SelectList(Model.FlatList, "ID", "Name"), "--Select--", new { #class = "form-control" })
</td>
<td>
#Html.EditorFor(model => model.GSC_ENG_FT_2, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
</table>
Partial view model:
namespace EMSD.Module.Misc.Model
{
public class UpdateGasSupplierViewModel
{
public string GSC_ID { get; set; }
public string GSC_COY_ENAME { get; set; }
}
}
Parent controller method:
[HttpPost]
public ActionResult _CPNCaseDetail(CPNDetailViewModel model)
{
string Post = Session["user_post"].ToString();
if (ModelState.IsValid)
{
cPNCaseService.Save(model);
}
return RedirectToAction("Case", "Case", new { Id = model.CASE_ID, Id2 = queueId, Id3 = "", Id4 = "Y" });
}
You need to use Templated helpers
Templated helpers are different than partials in that special contextual information from the parent is passed down to the child as long as we’re using the Html.EditorXyz() HtmlHelper methods.
Check This
Related
I am quite new to ASP.NET and MVC and I'm currently trying the following:
Model: Properties of the form
View: Display a form to the user
Controller:
Action: Do something
Go back to initial view and display values to user
With normal html I got this to work. With razor syntax I so far did not manage to re-display the values after the form was submitted.
My model:
namespace MyModels
{
public class SubmitTicketFormModel
{
[DisplayName("First Name")]
public string _firstName { get; set; }
[DisplayName("Last Name")]
public string _lastName { get; set; }
}
}
My View:
#model MyModels.SubmitTicketFormModel
#{
ViewData["Title"] = "SubmitTicketView";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Request</h1>
#using (Html.BeginForm("SubmitTicketAction", "SubmitTicketContoller", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(model => model._firstName)
#Html.TextBoxFor(model => model._firstName, new { #class = "form-control" })
#Html.LabelFor(model => model._lastName)
#Html.TextBoxFor(model => model._lastName, new { #class = "form-control" })
</div>
<input type="submit" value="Post comment" />
}
<table class="table table-bordered table-sm">
<thead class="thead-light">
<tr>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<td>
#Model._firstName
</td>
<td>
#Model._lastName
</td>
</tr>
</tbody>
</table>
Controller:
public class SubmitTicketController : Controller
{
public ActionResult SubmitTicketView()
{
var TicketInstance = new SubmitTicketFormModel();
return View(TicketInstance);
}
[HttpPost]
public ActionResult SubmitTicketAction(SubmitTicketFormModel model)
{
var NewTicketInstance = new SubmitTicketFormModel()
{
_firstName = model._firstName,
_lastName = model._lastName
};
return View(NewTicketInstance);
}
}
}
Can you please guide me in the right direction?
If you want the same View to render after the user clicks on submit button, then I guess you don't want that #using (Html.BeginForm("SubmitTicketAction", "SubmitTicketContoller", FormMethod.Post)) in the UI to show up again. Only the values of first name and last name in your view of which you've written your logic down in your view.
In that case, you can just pass a ViewBag in your view from controller which will help your View understand whether it has to show the input form or display user's entered data.
[HttpPost]
public ActionResult SubmitTicketAction(SubmitTicketFormModel model)
{
var NewTicketInstance = new SubmitTicketFormModel()
{
_firstName = model._firstName,
_lastName = model._lastName
};
ViewBag.Check = "true";
return View(ViewName , modelname);
}
And then in your view,
#model MyModels.SubmitTicketFormModel
#{
ViewData["Title"] = "SubmitTicketView";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#if(ViewBag.Check != null)
{
<h1>Request</h1>
#using (Html.BeginForm("SubmitTicketAction", "SubmitTicketContoller", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(model => model._firstName)
#Html.TextBoxFor(model => model._firstName, new { #class = "form-control" })
#Html.LabelFor(model => model._lastName)
#Html.TextBoxFor(model => model._lastName, new { #class = "form-control" })
</div>
<input type="submit" value="Post comment" />
}
}
else
{
<table class="table table-bordered table-sm">
<thead class="thead-light">
<tr>
<th>col1</th>
<th>col2</th>
</tr>
</thead>
<tbody>
<tr>
<td>
#Model._firstName
</td>
<td>
#Model._lastName
</td>
</tr>
</tbody>
</table>
}
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);
}
I need to bind a List inside a nested class to my ActionMethod.
Now, on calling the ActionMethod (look below), ActionItemList is null
Unfortunately i can't move the List into the main Model.
This is my main Model:
public class StateViewModel
{
public EmergencyOperationActionListModel ActionListModel { get; set; }
public EmergencyInfoModel InfoModel
public EmergencyInfoCauseListModel CauseListModel { get; set; }
}
and the nested one:
public class EmergencyInterventiActionListModel
{
public string Firefighters { get; set; }
public string ExternalAssistance { get; set; }
public string PlacesDescription { get; set; }
public List<ActionItemModel> ActionItemList { get; set; }
}
The view:
#model Emergencies.Models.StatoViewModel
//...code code code
#using (Html.BeginForm("EditOps", "Operations")
{
<table class="table table-responsive table-hover" style="margin-bottom: 0px;">
<thead class="headOperations">
<tr>
<td>
CompanyName
</td>
<td>
Workers
</td>
<td>
Due Date
</td>
<td>
Start Date
</td>
<td>
End Date
</td>
<td>
Action
</td>
</tr>
</thead>
#if (Model.ActionListModel != null)
{
for (int i = 0; i < Model.ActionListModel.ActionItemList.Count(); i++)
{
<tr>
<td>
#Html.HiddenFor(m=>m.ActionListModel.ActionItemList[i].Id)
#Html.EditorFor(m => m.ActionListModel.ActionItemList[i].CompanyName, new { htmlAttributes = new { id = "companyEdit_" + Model.ActionListModel.ActionItemList[i].Id, #class = "editBoxForInterventi" } })
</td>
<td>
#Html.EditorFor(m => m.ActionListModel.ActionItemList[i].NumberOfWorkers, new { htmlAttributes = new { id = "workersEdit_" + Model.ActionListModel.ActionItemList[i].Id, style = "width:40px", #class = "editBoxForInterventi" } })
</td>
<td>
<div class="input-group date" id="duedateCalendar_#Model.ActionListModel.ActionItemList[i].Id">
#Html.EditorFor(m => m.ActionListModel.ActionItemList[i].DueDate, new { htmlAttributes = new { onclick = "CalendarDue('" + Model.ActionListModel.ActionItemList[i].Id + "')", id = "duedateEdit_" + Model.ActionListModel.ActionItemList[i].Id, #class = "editBoxForInterventi form-control dueDateCalendar", #readonly = "readonly" } })
</div>
</td>
<td>
<div class="input-group date" id="starttimeCalendar_#Model.ActionListModel.ActionItemList[i].Id">
#Html.EditorFor(m => m.ActionListModel.ActionItemList[i].StartTime, new { htmlAttributes = new { id = "starttimeEdit_" + Model.ActionListModel.ActionItemList[i].Id, #class = "editBoxForInterventi form-control starttimeCalendar", #readonly = "readonly" } })
</div>
</td>
<td>
<div class="input-group date" id="endtimeCalendar_#Model.ActionListModel.ActionItemList[i].Id">
#Html.EditorFor(m => m.ActionListModel.ActionItemList[i].EndTime, new { htmlAttributes = new { id = "endtimeEdit_" + Model.ActionListModel.ActionItemList[i].Id, #class = "editBoxForInterventi form-control endtimeCalendar", #readonly = "readonly" } })
</div>
</td>
<td></td>
</tr>
}
}
</table>
<button type="submit" class="submit-with-icon btn btn-flussi-add" name="doButton" value="save">
<span class="glyphicon glyphicon-pencil"></span>
</button>
}
//code code code...
And finally the controller:
public ActionResult EditOps( List<ActionItemModel> ActionItemList )
{
//code
}
Just change your EditOps method signature to have the below.
public ActionResult EditOps(StateViewModel modelPosted)
{
//access modelPosted here.
}
The whole model is serialized as per the #model directive in your view.
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.
I have a view using a viewmodel.
In this view, I am using a partial view inside the #using (Html.BeginForm()) block code as given below
#foreach (var party in Model.Participants)
{
Html.RenderPartial("BlankEditorRow", party);
}
Partial view has some text box fields, user can enter data in these fields.
Now submit button is not placed inside partial view instead it in main view.
In my view when i click on submit button, i get null values in the viewmodel
[HttpPost]
public ActionResult ActionName(ViewModel model)
{
}
I'm not sure about how to get the post data from partial views. Can anyone please help me understand how to post data from partial view? example would be a big help
Edit: Partial View given below :
#model ASPNETMVCApplication.Models.Administration.Account.PartyModel
#using HtmlHelpers.BeginCollectionItem
<tr class="editorRow">
#using (Html.BeginCollectionItem("party"))
{
<td>#Html.TextBoxFor(m => m.FirstName, new { #style = "width: 100px;" })
</td>
<td>#Html.TextBoxFor(m => m.LastName, new { #style = "width: 100px;" })
</td>
<td>
#Html.DropDownListFor(model => model.PartyPersonalDetail.Gender, new SelectList(Model.Gender, "Id", "Name"), new { #style = "width: 100px;" })
</td>
<td>#Html.TextBoxFor(m => m.PartyPersonalDetail.MobilePhone, new { #style = "width: 100px;" })
</td>
<td>
#Html.DropDownListFor(model => model.PartyPersonalDetail.GothraId, new SelectList(Model.Gothras, "Id", "GothraName"), "--Don't Know--", new { #style = "width: 122px;" })
</td>
<td>
#Html.DropDownListFor(model => model.PartyPersonalDetail.NakshtraId, new SelectList(Model.Nakshtras, "Id", "NakshtraName"), "--Don't Know--", new { #style = "width: 122px;" })
</td>
<td>#Html.TextBoxFor(m => m.PartyPersonalDetail.EMail1, new { #style = "width: 135px;" })
</td>
<td>
Delete
</td>
}
</tr>
In order to post collections in MVC, they have to be indexed, so instead of that foreach, you need a for loop.
Try this:
#for(int i = 0; i < Model.Participants.Count; i++)
{
Html.RenderPartial("BlankEditorRow", Model.Participants[i]);
}
Use editor template.
Let's assume your Viewmodel is like this
public EventViewModel
{
public int ID { set;get;}
public string EventName { set;get;}
public List<Participant> Participants {set;get;}
public EventViewModel()
{
Participants=new List<Participant>();
}
}
public class Participant
{
public string FirstName { set;get;}
public string LastName { set;get;}
}
Create a Folder Called "EditorTemplates" under ~/Views/yourControllerNameFolder/ and create a view (the editor template) with the name Participant.cshtml.
Now add the code for your editor template
#model Participant
<p>
#Html.TextBoxFor(x=>x.FirstName)
</p>
<p>
#Html.TextBoxFor(x=>x.LastName)
</p>
Now in your Main View, Use the Html.EditorFor HTML helper method to call this editor template.
#model EventViewModel
#using (Html.BeginForm())
{
<p>Event Name</p>
#Html.TextBoxFor(x => x.EventName)
#Html.EditorFor(x=>x.Participants)
<input type="submit" value="Save" />
}
Now when you post the form, you will get the Participant information in the Participants collection of your viewmodel.