Post MVC ViewModel data to controller through JQuery - c#

I have the following models:
public class ColourCounts
{
[Key]
public int ColourGroup { get; set; }
public int ColourCount { get; set; }
public bool Selected { get; set; }
}
public class SizeCounts
{
[Key]
public int SizeGroup { get; set; }
public int SizeCount { get; set; }
public bool Selected { get; set; }
}
public class New
{
public New()
{
this.Newz = new New();
this.Colour = new ColourCounts();
this.ColourList = new List<ColourCounts>();
this.Size = new SizeCounts();
this.SizeList = new List<SizeCounts>();
}
public New Newz { get; set; }
public ColourCounts Colour { get; set; }
public List<ColourCounts> ColourList { get; set; }
public SizeCounts Size { get; set; }
public List<SizeCounts> SizeList { get; set; }
}
In my Index view I have
#model ...Models.New
...
<div id="colourTable">
#Html.Partial("_ColourCounts")
<div class="spinner">
</div>
<div>Loading...</div>
</div>
<div id="sizeTable">
#Html.Partial("_SizeCounts")
<div class="spinner">
</div>
<div>Loading...</div>
</div>
The partial view for
_ColourCounts
&
_SizeCounts
are
#model ...Models.New
<tbody>
<tr>
#Html.EditorFor(model => model.ColourList)
</tr>
</tbody>
&
#model ...Models.New
<tbody>
<tr>
#Html.EditorFor(model => model.SizeList)
</tr>
</tbody>
The editor templates are
#model ..Models.SizeCounts
<tr>
<td>
#Html.HiddenFor(m => m.SizeGroup)
#Html.DisplayFor(m => m.SizeGroup)
</td>
<td>
#Html.HiddenFor(m => m.SizeValue)
#Html.DisplayFor(m => m.SizeValue)
</td>
<td">
#Html.HiddenFor(m => m.SizeCount)
#Html.DisplayFor(m => m.SizeCount)
</td>
<td>#Html.CheckBoxFor(m => m.Selected)</td>
</tr>
&
#model ..Models.ColourCounts
<tr>
<td>
#Html.HiddenFor(m => m.ColourGroup)
#Html.DisplayFor(m => m.ColourGroup)
</td>
<td>
#Html.HiddenFor(m => m.ColourValue)
#Html.DisplayFor(m => m.ColourValue)
</td>
<td">
#Html.HiddenFor(m => m.ColourCount)
#Html.DisplayFor(m => m.ColourCount)
</td>
<td>#Html.CheckBoxFor(m => m.Selected)</td>
</tr>
I asynchronously load these by which is on the index view
<script type="text/javascript" name ="Size">
$(document).ready(function () {
//var val = $('#yearSelect3').val();
$.ajax({
url: "/News/_SizeCounts",
type: "GET",
})
.done(function (partialViewResult) {
$("#sizeTable").html(partialViewResult)
});
});
</script>
<script type="text/javascript" name="Colour">
$(document).ready(function () {
//var val = $('#yearSelect3').val();
$.ajax({
url: "/News/_ColourCounts",
type: "GET",
})
.done(function (partialViewResult) {
$("#colourTable").html(partialViewResult)
});
});
</script>
Whenever a user Checks any of the checkboxes, I want to capture ALL of the values (thee Newz can be ingored as that won't be re-rendered), the checkboxes and the hidden for values and post back to a controller
public ActionResult ReCalc(New model)
{
....
}
That then will get some new counts using a Linq query and I'll re-render the EditorTemplates in the Partial views as on the page load but with the new data.
I can't capture the form data in a way that I can pass it to the model in the ReCalc controller though.
I have tried in jquery using
var x = $('#myForm').serializeArray();
var y = JSON.stringify(x);
while the jason is "valid" according to http://jsonlint.com/ I get
{"name":"SizeList[0].Selected","value":"true"},{"name":"SizeList[0].Selected","value":"false"}
So clearly a problem there, and also the model is null in the controller when looking at in in debug.
Really appreciate any help to get the jquery right for this.
If you need any further information please let me know in layman's terms, I'm a T-SQL guy :) Thanks!

Related

Can't pass an enumerable model to a controller?

I'm a bit confused because I thought this a very straight-forward thing, it's possibly something simple tripping me up.
I have a view:
#model IEnumerable<CarViewModel>
#using (Html.BeginForm("SummarySaveAll", "VroomVroom", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
<table>
<thead>
<tr>
<th width="1">
#Html.DisplayNameFor(model => model.Driver)
</th>
<th width="1">
#Html.DisplayNameFor(model => model.Colour.Name)
</th>
</tr>
</thead>
<tbody>
#foreach (var element in Model)
{
<tr>
<td width="1">
#Html.DisplayFor(m => element.Driver)
</td>
<td width="1">
#Html.DropDownListFor(m => element.Colour, element.Colours, "Unknown")
</td>
</tr>
}
</tbody>
</table>
<div>
<input type="submit" value="Save Changes" class="btn" />
#Html.ActionLink("Cancel Changes", "Index", null, new { #class = "btn" })
</div>
</div>
}
and the list/enumerable of CarViewModel is supposed to bounce back to the VroomVroom controller, action SummarySaveAll which it does - but the viewmodel on the page doesn't get passed back to it:
[HttpPost]
public ActionResult SummarySaveAll(IEnumerable<CarViewModel> summaries)
{
// Want to do stuff with summaries but it's always null
return View();
}
I tried to encapsulate the List in another ViewModel and cycle through elements using a for i loop but that wouldn't pass back to the controller either.
Surely it's possible to send a List or IEnumerable of models back to a controller?
My CarVM:
public class CarViewModel
{
[MaxLength(150)]
[Display(AutoGenerateField = true, Name = "Entered By")]
public string Driver { get; set; }
[Display(AutoGenerateField = true)]
public Colour Colour { get; set; }
[Key]
[Display(AutoGenerateField = false)]
public int Id { get; set; }
[Display(AutoGenerateField = false)]
public bool IsDeleted { get; set; } = false;
public IEnumerable<SelectListItem> Colours { get; set; }
public CarViewModel() { }
public CarViewModel(Model CarModel summaryModel, CarPropertyCollection propertyCollection)
{
Driver = summaryModel.Driver;
Id = summaryModel.Id;
IsDeleted = summaryModel.IsDeleted;
Colour = summaryModel.Colour == null ? null :
propertyCollection.Colours.Where(x => x.Id == summaryModel.Colour.Id).FirstOrDefault();
Colours = propertyCollection.Colours.Select(x => new SelectListItem { Value = x.Id.ToString(), Text = x.Name });
}
}
}
Must stress that Colour is a custom class but only has Id and Name properties
Colours doesn't relate to a specific car, it relates to cars in general, so rather than using a collection as your view model, create a wrapper:
class EditCarsViewModel
{
public IEnumerable<SelectListItem> Colours { get; set; }
public IList<CarViewModel> Cars { get; set; }
}
Then your view:
#model EditCarsViewModel
#for (int i = 0; i < Model.Cars.Length; i++)
{
<td>
#Html.DropDownListFor(m => Model.Cars[i].Colour, Model.Colours, "Unknown")
</td>
}
Any other CarViewModel properties will need their own input as well. HiddenFor can be used if they should be readonly:
#model EditCarsViewModel
#for (int i = 0; i < Model.Cars.Length; i++)
{
#Html.HiddenFor(m => Model.Cars[i].Id)
#Html.HiddenFor(m => Model.Cars[i].Driver)
<!-- etc. -->
<td>
#Html.DropDownListFor(m => Model.Cars[i].Colour.Id, Model.Colours, "Unknown")
</td>
}
And your controller:
[HttpPost]
public ActionResult SummarySaveAll(EditCarViewModel model)
{
// model.Cars should be populated
return View();
}
Note that an indexable collection, such as IList<T> should be used, as the form field names need to include the index to differentiate the items.
Edit by OP
The Colour class consists of a [Key] int Id property and a string Name property. For DropDownList items I had to make sure the Id property was specified on the m => Model.Cars[i].Colour.Id line otherwise that particular prop was coming back as null even though other items were coming through fine.
try
[HttpPost]
public ActionResult SummarySaveAll(IList<CarViewModel> summaries)
{
// Want to do stuff with summaries but it's always null
return View(summaries);
}
I've also added this model as a param for your view
This how you do it:
First my View which posts back to a controller named Home and an action named ListView:
#model List<MyModel>
#{
ViewData["Title"] = "Using a list as model";
}
<h1>#ViewData["Title"]</h1>
#using (Html.BeginForm("ListView", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div>
<table>
<thead>
<tr>
<th width="1">
Name
</th>
<th width="1">
Description
</th>
</tr>
</thead>
<tbody>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td width="1">
#Html.DisplayFor(m => Model[i].Name)
</td>
<td width="1">
#Html.TextBoxFor(m => Model[i].Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<input type="submit" value="Save Changes" class="btn" />
#Html.ActionLink("Cancel Changes", "Index", null, new { #class = "btn" })
</div>
</div>
}
Notice how I used an indexer to render the controls [i]
This is my model:
public class MyModel
{
public string Name { get; set; }
public string Description { get; set; }
}
This is my controller action:
[HttpPost]
public IActionResult ListView(IEnumerable<MyModel> model)
{
return View(model);
}
And this is the result:

How to display an image from database with <PagedList> in MVC 4 EF 6

This challenge is bugging me for days now. I am obviously doing something wrong, but I wish I knew what.
How can I display my pictures in my Index View when using a PagedList class?
I cannot get a picture to display properly, when using the PagedList Class. All works just fine in my Edit View when using #model HeHu.Models.Candidate, but when trying to show the pictures in my Index View that is using PagedList #model PagedList.IPagedList<HeHu.Models.Candidate>, the field Model.PictFiles is not recognized as in the following code:
#if (Model.PictFiles.Any(.....)
<div class="col-md-10">
<img width="150" src="~/PictFile?id=#Model.PictFiles.First(.....)
</div>
</div>
}
Picture of red-underlined code
What I want to achieve:
Displaying records of candidates per row, including the picture.
The models are the following:
Candidate:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace HeHu.Models
{
public class Candidate
{
public int CandidateID { get; set; }
public int CsearchID { get; set; }
[StringLength (50)]
public string CandLastName { get; set;
public string CandFirstName { get; set; }
public string CandCompany { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
public virtual Csearch Csearch { get; set; }
public virtual ICollection<CandAction> CandAction { get; set; }
public virtual ICollection<PictFile> PictFiles { get; set;}
public virtual ICollection<FilePath> FilePaths { get; set; }
}
}
Pictfile:
using System.ComponentModel.DataAnnotations;
namespace HeHu.Models
{
public class PictFile
{
public int PictFileId { get; set; }
[StringLength(255)]
public string PictFileName { get; set; }
[StringLength(100)]
public string ContentType { get; set; }
public byte[] Content { get; set; }
public FileType FileType { get; set; }
public int CandidateId { get; set; }
public virtual Candidate Candidate { get; set; }
}
}
The Controller for the index is (simplified) as follows:
public class CandidateController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
public ActionResult Index(string sortOrder, string currentfilter, string searchString, int? opdrachtNummer, int? id, int? page)
{
//Adding the Pager
if (searchString != null || opdrachtNummer.HasValue)
{
page = 1;
}
else
{
searchString = currentfilter;
}
ViewBag.Currentfilter = searchString;
var candidates = from c in db.Candidates
.Include(c => c.PictFiles)
.Include(c => c.FilePaths)
select c;
int pageSize = 10;
int pageNumber = (page ?? 1);
return View(candidates.ToPagedList(pageNumber, pageSize));
}
And the controller for the image:
using HeHu.DAL;
using HeHu.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace HeHu.Controllers
{
public class PictFileController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: PictFile
public ActionResult Index(int id)
{
var pictFileToRetrieve = db.PictFiles.Find(id);
return File(pictFileToRetrieve.Content, pictFileToRetrieve.ContentType);
}
}
}
Finally, the View looks like this:
#model PagedList.IPagedList<HeHu.Models.Candidate>
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Candidates";
}
<h2><cr/>Kandidaten</h2>
#using (Html.BeginForm("Index", "Candidate", null, FormMethod.Get, new { enctype = "multipart/form-data" }))
{
<table class="table">
<tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CandLastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CandFirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CandCompany)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.CandidateID }) |
#Html.ActionLink("Details", "Details", new { id = item.CandidateID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.CandidateID })
</td>
</tr>
}
</table>
}
<br />
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",
new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
In you Edit View it's normal it works the way you use the helper:
#if (Model.PictFiles.Any(.....)
<div class="col-md-10">
<img width="150" src="~/PictFile?id=#Model.PictFiles.First(.....)
</div>
</div>
}
Model here refers to the Candidate type. However in your Index view you have a paged list of candidates, so in order to use the helper to show the picture for a given candidate, you should use the item in the collection you're iterating over:
Add a td to show the candidate's picture:
<td>
#if (item.PictFiles.Any(x => x.FileType == FileType.PersonalPicture))
{
<div class="col-md-10">
<img width="150" src="~/PictFile?id=#(item.PictFiles.First(x => x.FileType == FileType.PersonalPicture).PictFileId)"/>
</div>
}
</td>
Do note, however, that this time you can't ask for Model.PictFiles as Model is not a Candidate but a PagedList of them. Also, as you're iterating over the Model in a foreach loop, you can the use the foreach variable - item - for your purpose:
#foreach (var item in Model)
{
<tr>
<td>
#if (item.PictFiles.Any(x => x.FileType == FileType.PersonalPicture))
{
<div class="col-md-10">
<img width="150" src="~/PictFile?id=#(item.PictFiles.First(x => x.FileType == FileType.PersonalPicture).PictFileId)"/>
</div>
}
</td>
<td>
#Html.DisplayFor(modelItem => item.CandLastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CandFirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CandCompany)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.CandidateID }) |
#Html.ActionLink("Details", "Details", new { id = item.CandidateID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.CandidateID })
</td>
</tr>
}
Hope this helps!
Thanks Karel for both the right explanation and the right answer! It works perfectly. The final page is generated as follows. What I find interesting is the src="/PictFiles?id=1". It looks as if it stores the file in a directory and not in database.
<td>
<div class="col-md-10">
<img width="150" src="/PictFile?id=1" />
</div>
</td>

sending values to url string on dropdown selected value change in asp.net MVC

I have two tables. First is Development region and second is Zone. Zone has got RegionID as a foreign key. I would like to populate all the row from Zone table that is related with the Region selected from the dropdown list. I cannot figure out why the value is not being passed in url string. Please help me out and suggest the best way to accomplish it. Below are the models, controllers and view.
Model Zone
public class Zone
{
[Key]
public int ZoneID { get; set; }
[Required]
[Display(Name = "Zone Code")]
[RegularExpression(#"^[a-zA-Z]*$"), StringLength(5, ErrorMessage = "Code cannot be more than 5 charachter long")]
[Column("ZCode")]
public string ZoneCode { get; set; }
[Display(Name ="Zone"),RegularExpression(#"^[A-Z]+[a-z]*$"),Required]
public string ZoneName { get; set; }
public int RegionID { get; set; }
public virtual DevRegion devregion { get; set; }
[Required]
[Display(Name ="Active")]
public Boolean isActive { get; set; }
}
Model DevRegions
public class DevRegion
{
[Key]
public int RegionID { get; set; }
[Required]
[Display(Name = "Code")]
[RegularExpression(#"^[a-zA-Z]*$"), StringLength(5, ErrorMessage = "Code cannot be more than 5 charachter long")]
[Column("RCode")]
public string RegionCode { get; set; }
[Required]
[Display(Name ="Region")]
[Column("RName")]
[RegularExpression(#"^[A-Z]+[a-zA-Z\s-]*$", ErrorMessage ="Region can only consist of alphabets, space and dash")]
[StringLength(30,ErrorMessage ="Region cannot exceed 30 characters")]
public string RegionName { get; set; }
[Required]
[Display(Name ="Active")]
public Boolean isActive { get; set; }
}
ZonesController
public class ZonesController : Controller
{
private HuRISContext db = new HuRISContext();
// GET: Zones
public ActionResult Index(int? id)
{
ViewBag.RegionID = new SelectList(db.DevRegions, "RegionID", "RegionName");
var zones = db.Zones.Include(z => z.devregion).Where(x=>x.RegionID==(int)(id??x.RegionID));
return View(zones.ToList());
}
Index.cshtml
#model IEnumerable<HuRIS.Models.Zone>
....
<p>#Html.ActionLink("Create New", "Create")</p>
#using (Html.BeginForm("Index","Zones",FormMethod.Get))
{
#Html.AntiForgeryToken();
<div class="panel panel-info">
<div class="panel-body">
<div class="form-group center-block">
<label for="RegionID" class="control-label">Region:</label>
#Html.DropDownList("RegionID", null, "Show all Zones", htmlAttributes: new { #class = "form-control", #onchange = "this.form.submit();" })
</div>
</div>
</div>
}
<table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.devregion.RegionName)</th>
<th>#Html.DisplayNameFor(model => model.ZoneCode)</th>
<th>#Html.DisplayNameFor(model => model.ZoneName)</th>
<th>#Html.DisplayNameFor(model => model.isActive)</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.devregion.RegionName</td>
<td>#Html.DisplayFor(modelItem => item.ZoneCode)</td>
<td>#Html.DisplayFor(modelItem => item.ZoneName)</td>
<td>#Html.DisplayFor(modelItem => item.isActive)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ZoneID }) |
#Html.ActionLink("Details", "Details", new { id = item.ZoneID }) | #Html.ActionLink("Delete", "Delete", new { id = item.ZoneID })
</td>
</tr>
}
</table>
JQuery
$(document).ready(function () {
$(".form-control").change(function () {
$.ajax({
url: "~/ZonesController/Index",
type: 'GET',
cache: false,
data: { RegionID: $(".form-control").val() },
success: function (data) {
}
});
});
});
index method as shown below
public ActionResult Index()
{
ViewBag.Region = new SelectList(db.DevRegions, "RegionID", "RegionName");
var allzones = db.Zones.Include(z => z.devregion);
return View(allzones.ToList());
}
create new method as Shown below to accept the id selected on dropdown change event and create the partial view to load on the list of data from the table depending on what is selected on the dropdown:
public ActionResult ZoneList(int? id)
{
var zones = db.Zones.Include(z => z.devregion).Where(x => x.RegionID == (int)(id ?? x.RegionID));
return PartialView("~/Views/PartialViews/_ZoneList.cshtml", zones.ToList());
}
changed javascript as follows.
$("#Region").change(function () {
var selectedID = $(this).val();
$.get('/Zones/ZoneList/' + selectedID, function (data) {
$('.table').html(data);
//$('.table').fadeOut("linear");
//$('.table').fadeIn("linear");
});
});
});
on the index.cshtml changed the code as follows:
#model IEnumerable<HuRIS.Models.Zone>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken();
<div class="panel panel-info">
<div class="panel-body">
<div class="form-group center-block">
<label for="RegionID" class="control-label">Region:</label>
#Html.DropDownList("Region", null, "Show all Zones", htmlAttributes: new { #class = "form-control"})
</div>
</div>
</div>
}
#{
Html.RenderPartial("~/Views/PartialViews/_ZoneList.cshtml", Model);
}
partial view _ZoneList.cshtml
#model IEnumerable<HuRIS.Models.Zone>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.devregion.RegionName)
</th>
<th>
#Html.DisplayNameFor(model => model.ZoneCode)
</th>
<th>
#Html.DisplayNameFor(model => model.ZoneName)
</th>
<th>
#Html.DisplayNameFor(model => model.isActive)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.devregion.RegionName)
</td>
<td>
#Html.DisplayFor(modelItem => item.ZoneCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.ZoneName)
</td>
<td>
#Html.DisplayFor(modelItem => item.isActive)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ZoneID }) |
#Html.ActionLink("Details", "Details", new { id = item.ZoneID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ZoneID })
</td>
</tr>
}

Why is my form not populating my list on my view model?

When I build my form, my list populates correctly. However when I post back to my controller, the list SynonymTerm is null.
Here is my view model:
public class SynonymEditViewModel
{
public string Term { get; set; }
public List<SynonymTermEditViewModel> SynonymTerm;
public SynonymEditViewModel()
{
SynonymTerm = new List<SynonymTermEditViewModel>();
}
}
public class SynonymTermEditViewModel
{
public string Term { get; set; }
public string ReplacementTerm { get; set; }
public SynonymDuplicateWarning Warning { get; set; }
public SynonymTermEditViewModel()
{
Warning = new SynonymDuplicateWarning();
}
}
public class SynonymDuplicateWarning
{
public List<string> Terms { get; set; }
public SynonymDuplicateWarning()
{
Terms = new List<string>();
}
}
A simplified version of the view:
Edit.cshtml
#model MyProject.ViewModels.Synonyms.SynonymEditViewModel
<div class="form-group">
<div class="col-md-2">
#Html.LabelFor(model => model.Term)
</div>
<div class="col-md-10">
#Html.HiddenFor(model => model.Term)
#Html.DisplayFor(model => model.Term)
</div>
</div>
<table id="terms-table">
<tbody>
#Html.EditorFor(model => model.SynonymTerm)
</tbody>
</table>
EditorTemplates/SynonymTermEditViewModel.cshtml
#model MyProject.ViewModels.Synonyms.SynonymTermEditViewModel
<tr>
<td>
#Html.TextBoxFor(model => model.Term)
#Html.ValidationMessageFor(model => model.Term)
#Html.EditorFor(model => model.Warning)
</td>
</tr>
Here is the form data pulled from the browser request.
Term:Cat
SynonymTerm[0].Term:Feline
This data is passed to this controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(SynonymEditViewModel synonym)
{
if (ModelState.IsValid)
{
//breakpoint here
var dbSynonym = db.Synonym_Replacement_Term.Find(synonym.Term);
Mapper.Map(synonym, dbSynonym);
db.SaveChanges(User.Identity.Name, Request.ServerVariables["REMOTE_ADDR"]);
return RedirectToAction("Index");
}
return View(synonym);
}
The expected behavior is SynonymTerm is a list containing 1 object with Term="Feline", and all other properties having default/constructed values. Is there any reason SynonymTerm would be null?
I found the answer. In my ViewModel, I needed to add a getter/setter for the list:
public List<SynonymTermEditViewModel> SynonymTerm { get; set; }
Apparently they're required for the reflection used by MVC, according to this similar question.

Values for partial view model are null on submit

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.

Categories

Resources