I am trying to generate a list of checkboxes and post the selected item to post method of my controller but my view model is null.
Please see below code and help.
The view get invoke with the following button on another page -
<button class="btn btn-primary" id="historicalrecords"
onclick="location.href='#Url.Action("HistoricalWorkSubmissions", "Main", new {id= #Model.MessageIdsCombined.FirstOrDefault()})'">View Historical Works</button>
Model WorkSubmissions.cs:
public class HistoricalWorkSubmission
{
public string Society { get; set; }
public string Rsa { get; set; }
public DateTime ProcessingTime { get; set; }
public bool isSelected { get; set; }
}
public class HistoricalWorkSubmisssionViewModel
{
public List<HistoricalWorkSubmission> Submissions { get; set; }
}
Get method in MainController:
[HttpGet]
public async Task<ActionResult> HistoricalWorkSubmissions(string id)
{
WorkSearchViewModel workSearchViewModel = new WorkSearchViewModel
{
MessageId = id
};
var workSubmissions = await _swvManager.SearchAllWorkSubmissionsAsync(workSearchViewModel).ConfigureAwait(true);
return View("~/Views/Main/HistoricalWorkSubmissions.cshtml", workSubmissions);
}
HistoricalWorkSubmissions.cshtml:
#model SWV.WorkPicture.UI.Models.HistoricalWorkSubmisssionViewModel
#{
ViewBag.Title = "HistoricalSubmissions";
}
<h2>HistoricalSubmissions</h2>
#using (Html.BeginForm("HistoricalWorkSubmissions", "Main", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken();
<fieldset>
<div>
<table class="table-bordered">
#*#foreach (var submission in Model.Submissions)*#
#for (int i=0; i < Model.Submissions.Count(); i++)
{
var bmiWorks = Model.Submissions[i].Society + Model.Submissions[i].Rsa + " " + Model.Submissions[i].ProcessingTime;
<tr>
<td>
#Html.CheckBoxFor(m => Model.Submissions[i].isSelected)
#Html.Label(bmiWorks)
#Html.HiddenFor(m => Model.Submissions[i])
</td>
</tr>
}
</table>
<input class="button btn-primary" type="submit" value="Save"/>
</div>
</fieldset>
}
And finally post method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> HistoricalWorkSubmissions(HistoricalWorkSubmisssionViewModel workSubmissions)
{
WorkSearchViewModel workSearchViewModel = new WorkSearchViewModel();
workSearchViewModel.SwvId = "5124cfb4-afe8-4783-ab97-b9fbaaf6737d";
var workPicturesx = await _swvManager.SearchAllWorkSubmissionsAsync(workSearchViewModel).ConfigureAwait(true);
return View("~/Views/Main/HistoricalWorks.cshtml");
}
POST-
The value of abc is null in debugger. Please help.
Make sure the field names in the post match the model. The Label is not an issue, but CheckBoxFor and HiddenFor would generate Html input tags in the form posted to server.
#Html.CheckBoxFor(m => Model.Submissions[i].isSelected)
#Html.Label(bmiWorks)
#Html.HiddenFor(m => Model.Submissions[i].Society)
#Html.HiddenFor(m => Model.Submissions[i].Rsa)
#Html.HiddenFor(m => Model.Submissions[i].ProcessingTime)
Also I've removed the hidden field for submission because it's an object in your model, while we need to generate tags for each property instead.
Related
My GET method of controller construct and fill Model, which including Dictionary<int, MyClass>, and transmit that to View. But after, POST controller method get not null model with empty Dictionary.
Model:
public class CheckBoxItem
{
public string Name { get; set; }
public double Data { get; set; }
public bool Selected { get; set; }
}
public class CreateNewEventModel
{
[Required(ErrorMessage = "Error text")]
[Display(Name = "Header name")]
public string EventName { get; set; }
public Dictionary<int, CheckBoxItem> CheckBoxDataItems { get; set; }
public CreateNewEventModel()
{
CheckBoxDataItems = new Dictionary<int, CheckBoxItem>();
}
}
Controller:
public ActionResult CreateEvent()
{
CreateNewEventModel model = new CreateNewEventModel();
// FILL MODEL
foreach (var user in db.UsersInfo.ToList())
{
model.CheckBoxDataItems.Add(user.Id, new CheckBoxItem()
{
Name = user.Name,
Data = 0,
Selected = false
});
}
// THERE IS FULL MODEL
return View(model);
}
[HttpPost]
public ActionResult CreateEvent(CreateNewEventModel model)
{
// THERE IS model.Event name include text
// BUT model.CheckBoxDataItems is empty
if (ModelState.IsValid)
{
...
return View(model);
}
return View(model);
}
View:
#model HLyaa.Models.CreateNewEventModel
#{
ViewBag.Title = "Create Event";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Создание события</h2>
#if (Model.CheckBoxDataItems.Count() != 0)
{
using (Html.BeginForm("CreateEvent", "Events", FormMethod.Post))
{
#Html.ValidationSummary()
<div>
#Html.LabelFor(model => model.EventName)
<div>
#Html.EditorFor(model => model.EventName)
</div>
</div>
<table>
#foreach (var kvpair in Model.CheckBoxDataItems)
{
<tr>
<td>
#Html.CheckBoxFor(model => model.CheckBoxDataItems[kvpair.Key].Selected)
</td>
<td>
#Html.DisplayFor(model => model.CheckBoxDataItems[kvpair.Key].Name)
#Html.HiddenFor(model => model.CheckBoxDataItems[kvpair.Key].Selected)
#Html.HiddenFor(model => model.CheckBoxDataItems[kvpair.Key].Name)
</td>
<td>
#Html.TextBoxFor(model => model.CheckBoxDataItems[kvpair.Key].Data, new { #type = "number" })
</td>
</tr>
}
</table>
<br />
<input type="submit" value="Next" />
}
}
How I can transmit data inside dictionary from View to Controller?
Dictionary no, List/Array yes, but you will have to make some modifications.
Modify models
public class CheckBoxItem {
public int UserId { get; set; }
public string Name { get; set; }
public double Data { get; set; }
public bool Selected { get; set; }
}
public class CreateNewEventModel {
[Required(ErrorMessage = "Error text")]
[Display(Name = "Header name")]
public string EventName { get; set; }
public List<CheckBoxItem> CheckBoxDataItems { get; set; }
public CreateNewEventModel() {
CheckBoxDataItems = new List<CheckBoxItem>();
}
}
Modify GET method CreateEvent
public ActionResult CreateEvent() {
var model = new CreateNewEventModel();
//...FILL MODEL
foreach (var user in db.UsersInfo.ToList()) {
model.CheckBoxDataItems.Add(new CheckBoxItem() {
UserId = user.Id,
Name = user.Name,
Data = 0,
Selected = false
});
}
// THERE IS FULL MODEL
return View(model);
}
Update View
<table>
#for (var i = 0; i < Model.CheckBoxDataItems.Count; i++) {
<tr>
<td>
#Html.CheckBoxFor(model => model.CheckBoxDataItems[i].Selected)
</td>
<td>
#Html.DisplayFor(model => model.CheckBoxDataItems[i].Name)
#Html.HiddenFor(model => model.CheckBoxDataItems[i].UserId)
#Html.HiddenFor(model => model.CheckBoxDataItems[i].Selected)
#Html.HiddenFor(model => model.CheckBoxDataItems[i].Name)
</td>
<td>
#Html.TextBoxFor(model => model.CheckBoxDataItems[i].Data, new { #type = "number" })
</td>
</tr>
}
</table>
CheckBoxDataItems should be populated now when you post it to controller
As I answered in this post, you need to call "ToArray()[*]" on your dictionary before accessing its key and value so you can specify an index that's used by the ASP model binder to send your data back to the controller. ;)
I have flights timetable - Schedule view with list of flights
Where I just return View and have some filters and sorting.
Here is part of my view:
#model IEnumerable<AirPortIS.Models.Flight>
<div class="page-header">
<h3>Flights</h3>
</div>
<div id="modDialog" class="modal fade">
<div id="dialogContent" class="modal-dialog"></div>
</div>
<table class="table-bordered table-condensed">
<thead>
<tr>
<th>Flight №</th>
<th>Departure</th>
<th>Destination</th>
<th>#Html.ActionLink("Day", "Schedule", new { sort = ViewBag.SortDay, company = ViewBag.FiltrC, destination = ViewBag.FiltrD })</th>
<th>Departure Time</th>
<th>Arrival Time</th>
<th>Company</th>
<th>#Html.ActionLink("Seats", "Schedule", new { sort = ViewBag.SortSeats, company = ViewBag.FiltrC, destination = ViewBag.FiltrD })</th>
<th>#Html.ActionLink("Cost", "Schedule", new { sort = ViewBag.SortCost, company = ViewBag.FiltrC, destination = ViewBag.FiltrD })</th>
<th>Book ticket</th>
</tr>
</thead>
#foreach (var f in Model)
{
<tr>
<td>#Html.ActionLink(f.FlightId.ToString(), "FlightDetails", new { id = f.FlightId }, new {#class = "flItem" } )</td>
<td>#f.Departure</td>
<td>#f.Destination</td>
<td>#f.Day</td>
<td>#f.DepartureTime</td>
<td>#f.ArrivalTime</td>
<td>#f.Company.Name</td>
<td>#f.Seats</td>
<td>#f.Cost</td>
<td>#Html.ActionLink("Link for booking ticket")</td>
</tr>
}
</table>
I need to do that by clicking on a button "Book ticket" user is getting a page where dropdownlist have a preset value of FlightId.
For example we have a flight №1 and a link "Book ticket",so when user goes the booking ticket page he gets a droptdownlist with preselected value "1"
Here is my ticket Model
public class Tickets
{
public int Id { get; set; }
public int TicketId { get; set; }
public Flight Flight { get; set; }
public string Seat {get;set; }
public string Passenger { get; set; }
public int Flightid { get; set; }
public string Status { get; set; }
}
And part of TicketsController:
public class TicketsController : Controller
{
private readonly AirportContext _db = new AirportContext();
[Authorize]
public ActionResult Tickets()
{
var ticket = _db.Tickets.Include(t => t.Flight);
return View(ticket);
}
[HttpGet]
public ActionResult BookTicket()
{
IEnumerable<SelectListItem> statusList = new SelectList(new List<string> { "Book", "Buy" });
IEnumerable<SelectListItem> flights = new SelectList(_db.Flights.ToList(), "FlightId", "FlightId");
ViewData["flights"] = flights;
ViewData["statusList"] = statusList;
return View();
}
[HttpPost]
public ActionResult BookTicket(Tickets ticket)
{
IEnumerable<SelectListItem> statusList = new SelectList(new List<string> { "Book", "Buy" });
IEnumerable<SelectListItem> flights = new SelectList(_db.Flights.ToList(), "FlightId", "FlightId");
ViewData["flights"] = flights;
ViewData["statusList"] = statusList;
foreach (var c in _db.Tickets.ToList())
{
if ((_db.Tickets.ToList().Exists(x => c.TicketId == ticket.TicketId)) || (ticket.TicketId <= 0))
{
ModelState.AddModelError("TicketId", "Wrong ticket id");
}
if ((_db.Tickets.ToList().Exists(x => c.Seat == ticket.Seat)) && (_db.Tickets.ToList().Exists(x => c.Flightid == ticket.Flightid))
&& (_db.Tickets.ToList().Exists(x => c.TicketId == ticket.TicketId)))
{
ModelState.AddModelError("Seat", "The seat is unavailable");
}
if (_db.Tickets.ToList().Exists(x => c.Passenger == ticket.Passenger))
{
ModelState.AddModelError("Passenger", "The ticket has already bought");
}
}
if (ModelState.IsValid)
{
_db.Tickets.Add(ticket);
_db.SaveChanges();
return RedirectToAction("Tickets");
}
else return View(ticket);
}
And my BookTikcet View:
#model AirPortIS.Models.Tickets
#{
ViewBag.Title = "Book ticket";
}
<h2>Book ticket:</h2>
<form class="form-inline" method="post">
<div>
#Html.ValidationSummary()
</div>
<div class="form-group col-md-2">
Ticket №<br/>
#Html.EditorFor(model => Model.TicketId)
</div>
<div class="form-group col-md-1">
Flight №<br />
#Html.DropDownListFor(model => Model.Flightid, ViewData["flights"] as IEnumerable<SelectListItem>)
</div>
<div class="form-group col-md-2">
Место<br />
#Html.EditorFor(model => Model.Seat)
</div>
<div class="form-group col-md-2">
Passenger Name<br />
#Html.EditorFor(model => Model.Passenger)
</div>
<div class="form-group col-md-2">
Status<br />
#Html.DropDownListFor(model => Model.Status, ViewData["statusList"] as IEnumerable<SelectListItem>)
</div>
<div>
<input class="btn-success" type="submit" value="Book Ticket"/>
</div>
</form>
<div>
<form method="get" action="Tickets">
<button class="btn-danger" type="submit">Cancel</button>
</form>
</div>
I have no idea how to do it,so this whole code above just a standart code for creating a new ticket.
How I should modify code or add something to have this (For example we have a flight №1 and a link "Book ticket",so when user goes the booking ticket page he gets a droptdownlist with preselected value "1",for flight №2 on a page dropdownlist has a preselected value "2" for FlightId.
Hope that my question is clear,sorry if something is wrong written or not quite clear.
You need to pass the value of FlightId as a route (or query string) value to the BookTicket method. You link should be
#Html.ActionLink("Book ticket", "BookTicket", new { id = f.FlightId })
and modify the method to
[HttpGet]
public ActionResult BookTicket(int ID)
{
... // set you SelectLists as above
// Initialize your model and set the Flightid property
var model = new Tickets()
{
Flightid = ID
};
return View(model); // return the model to the view
}
Your dropdownlist will now have the option identified by Flightid selected when you first generate the view.
Note. I recommend you use a view model rather than your Tickets data model which will contain properties IEnumerable<SelectListItem> Flights and IEnumerable<SelectListItem> StatusList rather than using ViewData so that your view are strongly typed using
#Html.DropDownListFor(m => m.Flightid, Model.Flights)
You should also consider refactoring the code to populate the SelectLists into a private method so that you do not repeat code, for example
private void ConfigureViewModel(TicketVM model)
{
model.Flights = new SelectList(...);
model.StatusList = new SelectList(...);
}
Note also that it is a waste of resources to be calling your database to get the SelectList's in the POST method if ModelState is valid. Your code should be
if (!ModelState.IsValid)
{
ConfigureViewModel(model); // only necessary if you need to return the view
return View(model);
}
// save and redirect
Side note: It's unclear why you actually need a dropdownlist for Flightid in the BookTicket view. The user has already selected the flight so why are you giving the option to change it? It might be more appropriate to just render the Flightid as a hidden or readonly input so its submitted back to the POST method.
I have a table of data in a razor view, to which I added a checkbox for each row in the table.
I'm trying to return the checked list to my post action in the controller.
However the model shows as null on post back.
Model in view..
#model IPagedList<TrackerModel>
Post actionResult in controller....
[HttpPost]
public ActionResult Index(IList<TrackerModel> model)
{
return View(model);
}
The form tag is applied in another as the table is in a partial..
<div id="all-calibrations-grid" class="pull-left tracker-container">
#using (Html.BeginForm(FormMethod.Post))
{
{Html.RenderAction("AllCalibrations");}
}
</div>
Tracker ViewModel..
public class TrackerModel
{
public int Id { get; set; }
public string EquipmentID { get; set; }
public string EquipmentDescription { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime? ExpectedReturnedToCustomer { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime? DateOfCalibration { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime? NextDueDate { get; set; }
public bool StatusChange { get; set; } //01/07/2014
public string Status { get; set; }
public string CustomerName { get; set; }
}
All calibrations ...
[RoleAuthorization(Roles = "Customer User Passive,LTS User Passive")]
public PartialViewResult AllCalibrations(int? page, IPrincipal user)
{
int totalRecords;
// the filter model is fully populated
var filter = (CalibrationFilter)Session["_Filter"];
filter.PageSize = ((CalibrationFilter)Session["_Filter"]).PageSize;
filter.Page = page.HasValue ? page.Value - 1 : 0;
IList<Calibration> calibrationList;
if (user.IsInRole("LTS User Passive"))
{
LtsUser ltsUser = _ltsUserRepo.GetUser(user.Identity.Name);
// access the required data from the calibration repository
calibrationList = _calRepo.GetAllCalibrations(ltsUser.Customers, out totalRecords, filter);
}
else
{
CustomerUser custUser = _custUserRepo.GetUser(user.Identity.Name);
var customer = new List<Customer> { _custRepo.GetCustomer(custUser.Customer.Name) };
// access the required data (for a specific customer) from the calibration repository
calibrationList = _calRepo.GetAllCalibrations(customer, out totalRecords, filter);
}
var customerViewList = Mapper.Map<IList<Calibration>, IList<TrackerModel>>(calibrationList);
IPagedList<TrackerModel> pagedList = customerViewList.ToPagedList(filter.Page, filter.PageSize, totalRecords);
return PartialView("AllCalibrations", pagedList);
}
All Calibrations View...
#using InstrumentTracker.ViewModels.TrackerModels
#using MvcPaging
#model IPagedList<TrackerModel>
#{
Layout = null;
AjaxOptions ajaxOpts = new AjaxOptions
{
UpdateTargetId = "all-calibrations-grid",
HttpMethod = "POST"
};
}
#RenderPage("StatusLegend.cshtml")
<span>Displaying #Model.ItemStart - #Model.ItemEnd of #Model.TotalItemCount Calibrations</span>
<table id="all-calibrations" class="grid tracker-grid">
<colgroup>
<col class="workno-data">
<col class="equipmentId-data">
<col class="equipmentDesc-data">
<col class="calDate-data">
<col class="nextDueDate-data">
<col class="status-data">
</colgroup>
<thead>
<tr>
#* ADDED 23/06/2014 *#
#if (this.User.IsInRole("LTS Admin"))
{
<th id="SelectHeader">
<input type="submit" class="styledbutton" value="Save" /></th>
}
<th>Work<br />No.</th>
<th>ID</th>
<th>Description</th>
<th>Calibrated<br />On</th>
<th>Next<br />Due</th>
<th id="status-header">Status<a id="status-help" href="#">?</a></th>
#*Add the following to <th> tag if ? does not display correctly - style="text-overflow:clip;"*#
#* the customer column is only shown for LTS users since customer only see 1 customers data *#
#if (this.User.IsInRole("LTS User Passive"))
{
<th>Customer</th>
}
</tr>
</thead>
<tbody>
#* iterate through each calibration shown on this page *#
#for (int index = 0; index < Model.Count(); index++)
{
#Html.HiddenFor(m => Model.ElementAt(index).Id)
#Html.HiddenFor(m => Model.ElementAt(index).EquipmentID)
#Html.HiddenFor(m => Model.ElementAt(index).EquipmentDescription)
#Html.HiddenFor(m => Model.ElementAt(index).DateOfCalibration)
#Html.HiddenFor(m => Model.ElementAt(index).NextDueDate)
#Html.HiddenFor(m => Model.ElementAt(index).CustomerName)
<tr>
#*<th name="SelectCells" style="display:none;"><input type="checkbox" name="selectedCals" value="<m => Model.ElementAt(index).Id>"/></th>*#
#* ADDED 23/06/2014 *#
#if (this.User.IsInRole("LTS Admin"))
{
<th>#Html.EditorFor(m => Model.ElementAt(index).StatusChange, new { name = "selectedCals" })</th>
}
#* The work number is a link to the calibration the work no. represents *#
<td>#Html.ActionLink("WN–" + #Html.DisplayFor(m => Model.ElementAt(index).Id), "Index", "CalibrationViewer", new { id = Model.ElementAt(index).Id }, null)</td>
<td>#Html.DisplayFor(m => Model.ElementAt(index).EquipmentID)</td>
<td>#Html.DisplayFor(m => Model.ElementAt(index).EquipmentDescription)</td>
<td>#Html.DisplayFor(m => Model.ElementAt(index).DateOfCalibration)</td>
<td>#Html.DisplayFor(m => Model.ElementAt(index).NextDueDate)</td>
<td>#Html.DisplayFor(m => Model.ElementAt(index).Status)</td>
#* once again only the lts user sees the customer column data *#
#if (this.User.IsInRole("LTS User Passive"))
{
<td>#Html.DisplayFor(m => Model.ElementAt(index).CustomerName)</td>
}
</tr>
}
</tbody>
}
</table>
#* The page navigation for the recently completed table *#
<div class="pager">
#Html.Pager(Model.PageSize, Model.PageNumber, Model.TotalItemCount, ajaxOpts).Options(o => o.Action("AllCalibrations"))
</div>
If I remove the IList from the post actionResult, I just get the first selected model.
What am I doin wrong ??
What I do is have a hidden input in the view that holds a list of the selected records and then have that as a parameter on the controller action...
<input id="selectedRecords" name="selectedRecords" type="hidden" />
Populate the hidden input using javascript attached to the checkboxes, i.e. add an id to the hidden input when a checkbox is clicked, then on the controller action you can access it as a string; i think it even puts commas inbetween values automagically, using something like a selectrow function that will loop through the grid and put the selectedrow ids into the hidden input...
$.each(checkedIds, function (value) {
// stuff
});
EDIT:
Forget that each loop and have a read of this example on how to get the selected row data
Then get the ID, and store it in the hidden input, then on post on the controller action you simply get the hidden input value.
i'm using razor's listboxfor for the first time, but my Model is always null.
after reading similar posts and tryouts it still won't work.
Person.cshtml
#model SampleApp.Web.ViewModel.PersonViewModel
#{
ViewBag.Title = "Welcome";
}
<article>
<p>
Welcome to example page.
</p>
<p>
<div class="container">
//Post data works as expected, controllers create method write to db successfully
#using (Html.BeginForm("Create", "Person", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Personen</legend>
<div class="editor-label">
#* #Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Surrname)
</div>
</fielset>
</div>
<p>
<input type="submit" value="Create" />
</p>
}
//binding to Model fails, Model is null. Not be able to debug anything in controller action, it stops when "loading" the page
#using (Html.BeginForm("GetListBoxData", "Person"))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.ListBoxFor(model => model.ListboxData, Model.ListboxData);
}
</div>
PersonController.cs
[AcceptVerbs(HttpVerbs.Get)]
[ValidateAntiForgeryToken]
public ActionResult GetListBoxData()
{
var data = new List<PersonViewModel>();
data.Add(new PersonViewModel{Name = "Test", Surrname="testsurrname", Age=30});
var viewModel = new PersonViewModel()
{
ListboxData = data.AsEnumerable().Select(s=> new SelectListItem{Value=s.Name ,Text = s.Surrname}),
};
return View(viewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult GetListBoxData(PersonViewModel persondata)
{
//TODO: handle values from View
return View(this);
}
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "Name, Surrname, Age")] PersonViewModel persondata)
{
try
{
PersonService personDataProvider = new PersonService();
personDataProvider.SavePerson(persondata);
return new RedirectResult("SomewhereToGo");
}
catch (DataException ex)
{
//TODO: Log
}
return View(this);
}
PersonViewModel
public class PersonViewModel
{
public int PersonId{ get; set; }
public int Age { get; set; }
public string Name { get; set; }
public string Surrname { get; set; }
public IEnumerable<SelectListItem> ListboxData { get; set; }
}
writing values from editFor to db works as expected without code for listboxfor.
after adding it to my html it should be filled from db on page loading, but I get a ReferenceNotSet Exception on page loading. Model.ListboxData is null, before GetListBoxData action is called.
Thanks a lot for your help!
Your form should submit the data via POST, not GET. And, you don't need to use enctype = "multipart/form-data", unless you want to upload files through your from.
You need two Index Actions in your Controller, one is for sending the data from your Controller to the View, and the other one is for getting the data back from the View, when the form is submitted (POST) to the server.
The first argument you pass to your ListBox (the expression) refers to the Property in your Model that the selected item from your ListBox will be stored in, which in this case is PersonId.
So, your View should look like this:
#model MVCApplication.Web.ViewModel.PersonViewModel
#using (Html.BeginForm("Index", "Person"))
{
#Html.ListBoxFor(model => model.PersonId, Model.ListBoxData)
<input type="submit" value="Save" />
}
Then, in your Controller, you'll have two Actions like this:
public ActionResult Index()
{
var viewModel = new PersonViewModel()
{
ListboxData = data.Select(s => new SelectListItem { Value = s.PersonId.ToString(), Text = s.PersonId.ToString() }).AsEnumerable();
};
return View(viewModel);
}
[HttpPost]
public ActionResult Index(PersonViewModel viewModel)
{
// code to save the data in the database or whatever you want to do with the data coming from the View
}
By the way, in your ViewModel, you don't have to define your ListBoxData property like that, just do this:
public class PersonViewModel
{
public int PersonId{ get; set; }
public IEnumerable<SelectListItem> ListBoxData { get; set; }
}
I cant successfully post the values from my partial view to my action - all the properties are null.
Partial View Model:
public class AddressViewModel
{
public string ClientNumber { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Line3 { get; set; }
public string Suburb { get; set; }
public string PostalCode { get; set; }
}
Partial View:
#model Models.AddressViewModel
#{
Layout = null;
}
#using (Html.BeginForm("UseAddress", "Home"))
{
<div>
<table>
<tr>
<td>
<div class="display-label">
#Html.DisplayNameFor(model => model.Line1)
</div>
</td>
<td>
<div class="display-field">
#Html.DisplayFor(model => model.Line1)
</div>
</td>
........
</tr>
</table>
<input type="submit" name="UseAddress" id="submitbutton" value="Use Address" />
</div>
}
Action:
[HttpPost]
[Authorize]
public ActionResult UseAddress(AddressViewModel model)
{
return RedirectToAction("Index", "Home");
}
The partial view is rendered on the page by selecting a dropdown as follows:
<script type="text/javascript">
$(function () {
$('#AddressTypeDropdownList').change(function () {
var url = $(this).data('url');
$('#Address').load(url);
});
});
</script>
#Html.DropDownListFor(
x => x.SelectedAddressTypeId,
new SelectList(Model.AddressTypes, "Value", "Text"),
"-- Select Address Type --",
new
{
id = "AddressTypeDropdownList",
data_url = Url.Action("_Address", "Home")
}
)
<div id="Address"></div>
public ActionResult _Address()
{
AddressViewModel addressViewModel = new AddressViewModel {
ClientNumber = "test"
};
return PartialView(addressViewModel);
}
I would expect the UseAddress method to have the model.ClientNumber == "test" when I click the submit button but it is null...Is there anything obvious that I'm doing wrong?
DisplayFor doesn't create input for the field so it won't get posted. You'll need to add
#Html.HiddenFor(model => model.Line1)
....
To post the values.