I've seen many posts on SO considering this topic, though applying solutions didn't work for me and I am confused right now. Mb I'm missing sth?
Please consider I'm a noob at .js stuff.
So I get my values from dynamicly created form elements with this JS and attempt to post it:
EDIT 12:21: I got this script which should parse each element from form into custom made array resembling json. I still get null reference though. Got any idea how to get it?
var getValues = function (myForm) {
var array = [];
var parser;
$("formElement").each( function (i, elem) {
parser.empty()
parser = {
Id: $(elem,"#Id ").val(),
someOption: $(elem, "#someOption ").val(),
someText: $(elem, "#someText ").val(),
someNumber: $(elem, "#someNumber ").val()
}
array.push(parser);
});
console.log(array);
$.ajax({
type: "POST",
url: 'angus',
traditional: true,
data: {json: array },
success: function (data) {
$("#getData").empty();
$("#getData").append(array);
}
});
};
I get this in log:
(objects of index like i,i+1,i+2,i+3 match the viewmodels - is it right? and I have mixed feelings about those proto and functions - what is it?)
In my controller action I get null exception:
[HttpPost]
public ActionResult angus(IEnumerable<TrashViewModel> json)
{
return View(json.ToList());
}
I created my viewmodel:
[Serializable]
public class TrashViewModel
{
public int Id { get; set; }
public string someOption { get; set; }
public string someText { get; set; }
public string someNumber { get; set; }
}
I had my forms HTML attributes names match those of viemodel class.
EDIT:
html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="formExample" ng-controller="ExampleController">
<button class="btn btn-primary" ng-controller="addRow" ng-click="addLine()">Dodaj przycisk</button>
<form novalidate class="simple-form">
<div class="here">
<div class="formElement row">
<input type="hidden" name="Id" value="1"/>
<div class="col-md-2">
<select name="someOption" class="optns form-group col-md-12" ng-model="user.class">
<option selected value="1"> Rodzaj... </option>
<option value="test">2</option>
<option value="2">test</option>
<option value="2">2</option>
<option value="3">3</option>
#*tutaj beda dodane opcje*#
</select>
</div>
<div class="col-md-1">
<input name="someNumber" class="form-group col-md-12" type="number" ng-model="user.number" value="" text="Ilość..." /><br />
</div>
<div class="col-md-9">
<input name="someText" class="form-group col-md-12" type="text" ng-model="user.text" value="" text="Uwagi..." /><br />
</div>
</div>
</div>
<input type="button" value="Reset" />
<input type="submit" value="Save" />
</form>
</div>
appended html:
var strVar = "";
strVar += "<div class=\"formElement row\">";
strVar += " <input type=\"hidden\" name=\"Id\" value=\" "+ $scope.counter +"\"\/>";
strVar += " <div class=\"col-md-2\">";
strVar += " <select name=\"someOption\" class=\"optns form-group col-md-12\" ng-model=\"user.class\">";
strVar += " <option selected value=\"1\"> Rodzaj... <\/option>";
strVar += " <option value=\"test\">2<\/option>";
strVar += " <option value=\"2\">test<\/option>";
strVar += " <option value=\"2\">2<\/option>";
strVar += " <option value=\"3\">3<\/option>";
strVar += " #*tutaj beda dodane opcje*#";
strVar += " <\/select>";
strVar += " <\/div>";
strVar += " <div class=\"col-md-1\">";
strVar += " <input name=\"someNumber\" class=\"form-group col-md-12\" type=\"number\" ng-model=\"user.number\" value=\"\" text=\"Ilość...\" \/><br \/>";
strVar += " <\/div>";
strVar += " <div class=\"col-md-9\">";
strVar += " <input name=\"someText\" class=\"form-group col-md-12\" type=\"text\" ng-model=\"user.text\" value=\"\" text=\"Uwagi...\" \/><br \/>";
strVar += " <\/div>";
strVar += " <\/div>";
I end up with null exception which by what other posts suggest is because of viemodel class doesn't match the serialized objects. Don't know what to do at this point.
Thank you!
In order to POST your array, you need to stringify the data and set the contentType option. You ajax code needs to be
$.ajax({
type: 'POST',
url: '#Url.Action("angus")', // do not hard code url's
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ model: array }),
success: function (data) {
and the controller
[HttpPost]
public ActionResult angus(IEnumerable<TrashViewModel> model)
try replacing
var parsed = $(myForm).serializeArray();
with
var parameters = {
Id : $("#Id ").val(),
someOption : $("#someOption ").val(),
someText : $("#someText ").val(),
someNumber : $("#someNumber ").val()
};
then pass it to the submit
JSON.stringify(parameters)
in your JavaScript code, 3 things jump out at me:
you're using .serializeArray(), which creates an array of objects each with a name and value property. this does not match the structure of your TrashViewModel object
you're wrapping the serialized object inside a new object with a single property called "json", which adds more structure to your data
you're stringifying said object
all of that is unnecessary, since the .ajax() method will package the data in the correct format for you. you simply need to pass the serialized form as the data parameter.
data: $(myform).serialize()
on the controller, you should just set the parameter on the action to be your TrashViewModel object. please note that it's a single object, not an enumerable.
public ActionResult Angus(TrashViewModel form)
{
// do something
}
if you were to use .serializeArray(), then you'd need to create a model object with Name and Value properties so that the model binder can properly resolve the params.
// JavaScript
data: $(myform).serializeArray()
// Controller
public class NameValueModel
{
public string Name { get; set; }
public string Value { get; set; }
}
public ActionResult Angus(NameValueModel[] form)
{
// do something
}
I'm not 100% happy about outcome, because I still have to parse json string at the end on server side. I think I'll soon do Q&A, so others won't have to fight a week to do sth like this. Thanks to:
#StephenMuecke
#Emil
#Jeff M
So actually what I did:
js to get inputs and push it custom style then do post ajax request:
var array = [];
var parser;
$(".formElement").each( function (i, elem) {
//parser.empty()
parser = {
Id: $("#Id", $(this)).val(),
someOption: $("#someOption", $(this)).val(),
someText: $("#someText", $(this)).val(),
someNumber: $("#someNumber", $(this)).val()
};
console.log(parser);
array.push(parser);
});
console.log(array);
$.ajax({
type: "POST",
url: 'angus',
traditional: true,
data: { json: JSON.stringify(array) },
success: function (data) {
$("#getData").empty();
$("#getData").append(array);
}
});
controller:
(don't mind the logic, because it's useless here except it gave info during debugging)
the most important thing was to give string type as parameter; I'm 100% sure that my json bounced off of the complex type viewmodel
[HttpPost]
public ActionResult angus(string json)
{
var check = json.ToString() == null;
return RedirectToAction("ErrorAction");
}
Related
I am trying to create functionality that will update a product's quantity in the users shop cart. I am able to populate the ViewModel with the relevant data and display it in a table in the View.
In the script tags, I have two functions, one to increase the quantity of the product and the other to decrease the quantity in increments of 1. Now all works well if there is one product in the list. I receive the correct values. As soon as there are two or more products in the list, whenever the increase or decrease functions are fired, the values (quantity and productId) of the last item in Model.Products are sent to the 'UpdateQuantity' ActionMethod, instead of the values from the inputs in the selected table row.
For example: If there are two products in the list. Product A (Id:1 and Quantity: 3) and Product B(ID:2 and quantity:5), If I click on either the increase or decrease buttons next to Product A's quantity input, the relevant function will pass Product B's values (2 and 5) to the Action Method instead of Product A's values (1 and 3).
I'm assuming that there is a naming convention issue, but I'm unable to figure out why this is happening. Any help would be highly appreciated.
Below is what I have so far:
ViewModel:
public class ShopCartViewModel : BaseViewModel
{
public List<OrderDetail> OrderDetailList { get; set; }
public List<Order> OrderList { get; set; }
public List<Product> Products { get; set; }
}
Controller:
public List<Order> orderList = new List<Order>();
public List<OrderDetail> orderDetailList = new List<OrderDetail>();
public List<Product> productList = new List<Product>();
public ActionResult Index()
{
ShopCartViewModel vm = new ShopCartViewModel();
ConnectToDatabase();
User u = Helpers.GetUser.GetUserDetails();
orderList = GetAllOrdersForCustomer(u.Id);
GetOrderDetails();
vm.OrderList = orderList;
vm.OrderDetailList = orderDetailList;
vm.Products = productList;
return View(vm);
}
[HttpPost]
public ActionResult UpdateQuantity(string quantity, string productId)
{
//do stuff here
}
View:
#foreach(var product in Model.Products)
{
string class_quantity = "quantity_" + product.Id;
string class_productId = "productId_" + product.Id;
<div class="quantity">
<button class="dec-btn p-0" type="submit"><i class="fas fa-caret-left" onclick="q_dec()"></i></button>
<input name="quantity" id="#class_quantity" class=" form-control" type="text" value="#product.Quantity" />
<button class="inc-btn p-0" type="submit"><i class="fas fa-caret-right" onclick="q_inc()"></i></button>
<input name="productId" id="#class_productId" class=" form-control" type="text" value="#product.Id" style="visibility:hidden" />
<script type="text/javascript">
function q_inc(e) {
var p_quantity = $("##class_quantity").val();
var final_quantity = parseInt(p_quantity) + 1;
var p_productId = $("##class_productId").val();
$.ajax({
url: '#Url.Action("UpdateQuantity","ShopCart")',
type: 'POST',
data: {quantity: final_quantity, productId: p_productId },
success: function () {
alert("Increase Success");
}
})
}
function q_dec(e) {
var p_quantity = $("##class_quantity").val();
if (p_quantity >= 2) {
var final_quantity = parseInt(p_quantity) - 1;
}
var p_productId = $("##class_productId").val();
$.ajax({
url: '#Url.Action("UpdateQuantity","ShopCart")',
type: 'POST',
data: {quantity: final_quantity, productId: p_productId },
success: function () {
alert("Decrease Success");
}
})
}
</script>
</div>
}
The problem with your code is that in your loop you are duplicating functions q_inc(e) and q_dec(e)
You should fix your code with something like this:
#foreach(var product in Model.Products)
{
string class_quantity = "quantity_" + product.Id;
string class_productId = "productId_" + product.Id;
<div class="quantity">
<button class="dec-btn p-0" type="button" onclick="q_dec('#class_productId', '#class_quantity")'><i class="fas fa-caret-left"></i></button>
<input name="quantity" id="#class_quantity" class=" form-control" type="text" value="#product.Quantity" />
<button class="inc-btn p-0" type="button" onclick="q_inc('#class_productId', '#class_quantity')"><i class="fas fa-caret-right"></i></button>
<input name="productId" id="#class_productId" class=" form-control" type="text" value="#product.Id" style="visibility:hidden" />
}
<script type="text/javascript">
function q_inc(id, quantity) {
var p_id = $("#" + id);
var p_quantity = $("#" + quantity);
var quantity_val = p_quantity.val()
var final_quantity = parseInt(quantity_val) + 1;
var p_productId = p_id.val();
$.ajax({
url: '#Url.Action("UpdateQuantity","ShopCart")',
type: 'POST',
data: {quantity: final_quantity, productId: p_productId },
success: function () {
alert("Increase Success");
p_quantity.val(final_quantity);
}
})
}
function q_dec(id, quantity) {
// change this function accordingly
</script>
Im loading contents dynamically to table as you see i have an input and i have two Checkbox:
$.ajax({
type: "GET",
url: "/User/GetCustomerContactInfo",
data: { ids: items },
traditional: true,
dataType: 'json',
success: function (values) {
for (var i = 0; i < values.length; i++) {
value = values[i]
if (value != null) {
holderHTML += '<tr id="row' + value.CustomerNo + '">';
holderHTML += '<td><input id="NameOfCompany" name="[' + i + '].NameOfCompany" value="' + value.NameOfCompany + '" /></td>';
holderHTML += '<td><input id="checkboxCustom1" type="checkbox" name="[' + i + '].RightsCode" value="Åbne ordrer"/>
<input id="checkboxCustom1" type="checkbox" name="[' + i + '].RightsCode" value="Lukkede ordrer"/></td>
holderHTML += '</tr>';
}
}
$('#output').append(holderHTML);
},
error: function () {
console.log('something went wrong - debug it!');
}
})
And HTML Output will be like:
<form id="CustomerNEmployeeForm">
<table>
<tbody id="output">
<tr id="row10883">
<td>
<input type="text" id="NameOfCompany" name="[0].NameOfCompany" value="Center">
</td>
<td>
<input id="checkboxCustom1" type="checkbox" name="[0].RightsCode" value="Åbne ordrer">
<input id="checkboxCustom1" type="checkbox" name="[0].RightsCode" value="Fakturerede ordrer">
</td>
</tr>
</tbody>
</table>
</form>
<button class="btncreateusers" id="createusersJS" type="button" onclick="CreateCustomerNEmployees();">Create</button>
And than i want to get value of checkbox and pass to controller by Serialize form, but when form being Serialized, it will pass only value of first Checkbox:
function CreateCustomerNEmployees() {
var formdata = $("#CustomerNEmployeeForm").serializeArray();
console.log(formdata);
$.ajax({
"url": '#Url.Action("CreateCustomers", "User")',
"method": "POST",
"data": formdata ,
"dataType": "json",
complete: function () {
}
});
}
Output console.log(formdata):
0: {name: "[0].NameOfCompany", value: "Center"}
1: {name: "[0].RightsCode", value: "Åbne ordrer"}
2: {name: "[0].RightsCode", value: "Lukkede ordrer"}
Model:
public class CreateCustomers
{
public string NameOfCompany { get; set; }
public string RightsCode { get; set; }
}
Controller:
[HttpPost]
public JsonResult CreateCustomers(List<CreateCustomers> model)
{
if (model == null)
{
model = new List<CreateCustomers>();
}
var resultsOne = new List<Users>();
var resultsTwo = new List<Rettigheder>();
foreach (var item in model)
{
var UsersInsert = new Users
{
CompanyName = item.NameOfCompany,
//other property
};
var RettighederInsert = new Rettigheder
{
//other property
Rettighedskode = item.RightsCode
};
resultsOne.Add(UsersInsert);
db.Users.Add(UsersInsert);
resultsTwo.Add(RettighederInsert);
db.Rettigheder.Add(RettighederInsert);
}
db.SaveChanges();
return Json(model, JsonRequestBehavior.AllowGet);
}
Debug Output:
https://i.imgur.com/DT6TYd4.jpg
The CreateCustomers Model has specified RightsCode as a single string.
public class CreateCustomers
{
public string NameOfCompany { get; set; }
public string RightsCode { get; set; }
}
The MVC model binding in this case binds the first match only.
If you want all RightsCode checkboxes bound you need to change RightsCode to a string array.
public class CreateCustomers
{
public string NameOfCompany { get; set; }
public string[] RightsCode { get; set; }
}
Unrelated but good practice -
html tag id values should be unique. Names can be duplicated but id values that are not unique can cause problems with css/js selectors.
I have a jQuery script that captures a form into an object and is supposed to send that object to a controller method. Here's the script:
var modalConfirm = function (callback) {
$("#modal-btn-si").on("click", function () {
callback(true);
$("#modal-confirm").modal('hide');
});
$("#modal-btn-no").on("click", function () {
callback(false);
$("#modal-confirm").modal('hide');
});};
function confirmar(form, text) {
$("#modal-confirm").modal('show');
modalConfirm(function (confirm) {
if (confirm) {
enviar(form);
}
}); };
function enviar(form) {
debugger;
var datos = $('#' + form).serializeArray(),
dataObj = {};
$(datos).each(function (i, field) {
dataObj[field.name] = field.value;
});
if (typeof dataObj["precio"] === "undefined") { dataObj["precio"] = 0; }
$.post("NuevaOpcion", {
contentType: "application/JSON",
data: JSON.stringify(dataObj),
}); }
Note: the script was originally much simpler, but trying to fix the issue I'm describing forced me to divide the code in the functions you see.
I created a model to receive the form's data:
public class NuevaOpcionFormModel {
public NuevaOpcionFormModel() { }
public int Id { get; set; }
public string nombre { get; set; }
public int cantidad { get; set; }
public int precio { get; set; }
public int idrespuesta { get; set; }
public int OptionSelectedItem { get; set; }
}
And the controller's method signature:
[HttpPost]
public ActionResult NuevaOpcion (Dayvo.Presupuestador.Web.Models.Form.NuevaOpcionFormModel nuevaOpcion) { ... }
What I've tried
On the script:
.serialize() instead of .serializeArray().
Not serialize at all.
Passing entire 'form' into object and then to controller.
JSON.stringify (actual state) and not using it.
Stablishing each field in data manually.
Stablishing each field in data manually and apllying JSON.stringify.
On the controller:
[FromForm] & [FromBody]
[Bind]
A single variable for each field, matching names and types.
Everything I've tried ends up with the controller's method receiving nothing. I tracked the script (that's why you're seeing a debugger; breakpoint in it), it gets the object into the array correctly, each field with it's proper value:
But still hits the controller with empty object:
Any clue about what I'm doing wrong is more than welcome. Thanks in advance.
EDIT
As requested, here's the view part I'm capturing into the form:
<div class="panel-footer">
#using (Html.BeginForm("NuevaOpcion", "Home", FormMethod.Post, new { #id = "frm_nueva_opcion" })) {
#Html.HiddenFor(m => m.Id)
<div class="row">
<div class="col-md-6">
<div class="form-group" style="margin-bottom: .7em;margin-top: .7em;">
<button class="btn btn-success btn-xs" type="button" onclick=" $('#row-nueva-opcion').toggle()" id="add-opcion">
<span class="glyphicon glyphicon-plus-sign"></span> Añadir nueva opción
</button>
</div>
</div>
</div>
<div class="row" id="row-nueva-opcion" style="display:none">
<div class="col-md-10">
<label>
<input type="checkbox" id="opcion-extra" onclick=" $('#nuevo-precio').attr('disabled', !this.checked);" />
Es opción extra
</label>
<div class="input-group" style="margin-bottom:1.7em;">
<input type="text" placeholder="Opción" class="form-control" name="nombre" style="max-width:70%;">
<input type="number" placeholder="Cantidad" min="1" value="1" class="form-control" name="cantidad" style="max-width:15%;">
<input type="number" placeholder="Precio" class="form-control" id="nuevo-precio" name="precio" style="max-width:15%;" disabled>
<input type="hidden" name="idrespuesta" id="idrespuesta" value="#listItems.Select(x=>x.Value).FirstOrDefault()" />
<div class="input-group-addon">€</div>
<span class="input-group-btn">
<a class="btn btn-primary" data-title="Confirmación de acción" data-toggle="modal" data-target="#modal_confirm" onclick="confirmar('frm_nueva_opcion')">
<span class="glyphicon glyphicon-floppy-disk"></span> Guardar
</a>
</span>
</div>
</div>
<div class="col-md-8">
<div class="form-group">
<label>
¿Para que pregunta es la opción?
#Html.DropDownList("OptionSelectedItem", listItems, new { #class = "form-control" })
</label>
</div>
</div>
</div>
}
</div>
The jquery $.post() method sends data using the default contentType='application/x-www-form-urlencoded; charset=UTF-8' where the data needs to be PlainObject.
For the DefaultModelBinder to bind to your model, the name/value pairs of the object need to match the model properties, so the format needs to be
var data = { Id: someValue, nombre: anotherValue, .... };
To generate that object, either generate it manually, or better, use the .serialize() method (not .serializeArray()) to correctly serialize all form controls. Change the script to
function enviar(form) {
var data = $('#' + form).serialize();
$.post("NuevaOpcion", data, function(response) {
... // code to execute when the response is returned
});
Note it is not clear what you where expecting with the if (typeof dataObj["precio"] === "undefined") { dataObj["precio"] = 0; } code, but it is unnecessary and can be omitted - your precio property is int and it will have a value of 0 if it is not included in the request.
I also strongly recommend you use the HtmlHelper methods to strongly bind to your model, and to ensure the correct name, value and data-val-* attributes are added for 2-way model binding and client side validation.
Programming a ASP.net webapp to insert an entry into a database on form submit.
I've tried numerous configurations of find() and children() and they either
1) error
2) pass empty strings instead of what I type
This one errors like this:
Whats the correct way to select the individual children of myform?
Javascript (the first block here is the code I'm asking about)
var entry_array = [];
entry_array[0] = $('#myform').children('#01').css().text();
entry_array[1] = $('#myform').children('#02').css().text();
entry_array[2] = $('#myform').children('#03').css().text();
entry_array[3] = $('#myform').children('#04').css().text();
$(document).ready(function () {
$("#myform").submit(function () {
alert("Function ran");
$.ajax({
url: 'Home/SubmitEntry', //(rec)= Controller's-name
//(recieveData) = Action's method name
type: 'POST',
datatype: 'json',
traditional: true,
data: { 'entry_array': entry_array },
success: function(response) {
console.log(response);
},
error: function (response) {
console.log(response);
}
});
alert("Function finished running");
});
});
Controller
[HttpPost]
public ActionResult SubmitEntry(List<String> entry_array)
{
String firstname = entry_array[0];
String lastname = entry_array[1];
String town = entry_array[2];
String order = entry_array[3];
knightsEntities db = new knightsEntities();
int nextiD = 0;
nextiD = db.Apprentenceship_Sheet.ToList().Last().id + 1;
var newApprentenceship_Sheet = new Apprentenceship_Sheet();
newApprentenceship_Sheet.first_name = firstname;
newApprentenceship_Sheet.last_name = lastname;
newApprentenceship_Sheet.hailed_town = town;
newApprentenceship_Sheet.order = order;
newApprentenceship_Sheet.id = nextiD;
db.Apprentenceship_Sheet.Add(newApprentenceship_Sheet);
db.SaveChanges();
return View();
}
View
<script src='https://code.jquery.com/jquery-3.1.0.min.js'></script>
<script src="~/scripts/custom.js"></script>
#{
ViewBag.Title = "Home Page";
}
<div>
<form id= "myform" method="post">
First_name:<br>
<input type="text" id="01" name="firstname"><br>
Last_name:<br>
<input type="text" id="02" name="lastname"><br>
Town:<br>
<input type="text" id="03" name="town"><br>
Order:<br>
<input type="text" id="04" name="order"><br>
<br>
<input type='submit' id="05" name="Submit">
</form>
</div>
You can get the values of the text boxes directly by using $('#01').val(), or if you want refer it with reference to your form. You can use $('#myform').find('#01').val(). It will give the value of the text-box. Here is the jsfiddle for u.
$('#myform').find('#01').val()
$('#01').val()
http://jsfiddle.net/71weztcn/
I have controls that insert from jQuery. The controls can change depending on the option you choose before, that is, they are not controls have created statically, but to think through jQuery with the option you choose.
My question is is possible to access a list of controller in HttpPost?
This is the function that performed to insert controls:
function GetProperties() {
var subcategory = $("#ddlSubcategory").val();
$.getJSON("/AddAdBox/GetProperties?id=" + subcategory, null, function (data) {
$.each(data, function (i, item) {
//item.ID // PROPERTY ID
//item.NAME //NAME PROPERTY
//item.OPTION_PROPERTY[0].ID //ID OPTION ID
//item.OPTION_PROPERTY[0].NAME // NAME OPTION
//item.OPTION_PROPERTY.length // SI ES 0 ES TXT SINO SELECT
var itemlist = '';
//<div class="col-sm-6">
// <label>
// Título
// </label>
// <input type="text" name="email" class="form-control" placeholder="Título">
// </div><!-- /.col -->
if (item.OPTION_PROPERTY != null) {
if (item.OPTION_PROPERTY.length > 0) {
itemlist = '<div class="col-sm-6 animated" style="opacity:1;"><label>' + item.NAME + '</label>';
itemlist += '<select id="ddl"' + item.NAME + '">';
for (var i = 0; i < item.OPTION_PROPERTY.length; i++) {
itemlist += '<option value="' + item.OPTION_PROPERTY[i].ID + '">' + item.OPTION_PROPERTY[i].NAME + '</option>';
}
itemlist += '</selec>';
itemlist += '</div>';
}
}
else {
itemlist = '<div class="col-sm-6 animated" style="opacity:1;"><label>' + item.NAME + '</label>';
itemlist += '<input type="text" name="' + item.NAME + '" class="form-control" placeholder="' + item.NAME + '">';
itemlist += '</div>';
}
$("#properties").append(itemlist);
});
});
}
One way to bind data to a controller, from dynamic HTML elements, is by using a custom model binder. For example:
In my controller I use a viewmodel:
public class IndexViewModel
{
public int SelectedItemId { get; set; }
}
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new IndexViewModel());
}
[HttpPost]
public ActionResult Index(IndexViewModel viewModel)
{
return View(viewModel);
}
}
I then create a custom model binder that can work with that viewmodel:
public class IndexViewModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
string[] allKeys = HttpContext.Current.Request.Form.AllKeys;
var viewModel = bindingContext.Model as IndexViewModel;
viewModel.SelectedItemId = int.Parse(HttpContext.Current.Request.Form[0]);
}
}
In your Global.asax.cs file, place this in the Application_Start()
ModelBinders.Binders.Add(typeof(IndexViewModel), new IndexViewModelBinder());
In my view file I have:
#model SelectListModelBinding.Controllers.IndexViewModel
#{
ViewBag.Title = "Home Page";
}
#using (Html.BeginForm())
{
<div class="col-sm-6 animated" style="opacity:1;">
<label>FooName</label>';
<select name="ddlFooName" id="ddlFooName">
<option value="1">Item 1</option>
<option value="2">Item 2</option>
</select>
</div>
<input type="submit" value="Save" />
}
You can pretend that the <select> was dynamically generated. Now when I post back to the controller, the IndexViewModelBinder is executed and I can see the values passed in the Form property of the current request. I can then pick out whatever data I need. In my example I'm picking out the id of the selected list item from ddlFooName
Since the names of the dropdowns will be dynamic, you may have to do some stuff with the Form.AllKeys to pick out stuff that starts with "ddl" and use that key to get the data.