Can't pass array of objects to controller by jQuery AJAX - javascript

I tried to pass array of objects to controller by jQuery Ajax, but result is null in ASP.NET 5.0.
My data array is what send to controller: regions.
Data constructor is defined in BoundingBoxModel class.
This is my ajax function:
$("body").on("click", "#onClick", function () {
var regions = [];
var arr = Array.prototype.slice.call(document.getElementsByClassName('ui-draggable'));
arr.forEach((tagele) => {
var region = {};
region.Height = tagele.offsetHeight;
region.Width = tagele.offsetWidth;
region.Top = tagele.offsetTop;
region.Left = tagele.offsetLeft;
regions.push(region);
});
$.ajax({
url: '/GenCode/Addregions',
type: "POST",
dataType: "json",
contentType: "application/json;charset=utf-8",
data: JSON.stringify({'regions': regions}),
success: function () {
alert("pass")
},
error: function (jqXhr, json, errorThrown) {
alert(errorThrown);
console.log(errorThrown);
}
});
});
So this is my BoundingBoxModel:
public class BoundingBoxModel
{
public int BoundingBoxId { get; set; }
public double Top { get; set; }
public double Left { get; set; }
public double Height { get; set; }
public double Width { get; set; }
}
This is my action method. It's defined in GenCodeController.
[HttpPost]
public IActionResult AddRegions(List<BoundingBoxModel> regions)
{
JsonResult result = new JsonResult(this.Json(JsonConvert.SerializeObject(regions), System.Web.Mvc.JsonRequestBehavior.AllowGet));
return result;
}
My result is null:
I don't understand why it's happened. Can you help me?

There are some issues that I can see -
I am not sure if you explicitly written this logic but your region object will always have last value of arr because you declare your variable inside loop.
If you are trying to create an array then you should declare your region variable like - var region = []; .Right now it is an object.
You are trying to pass an object and accepting a list in webservice. Either remove the list in parameter in AddRegions service or pass a Array from ajax call.

I resolved my problem by deteting contentType: "application/json;charset=utf-8", line in ajax code.
Using this line make the array of region's type change to string so when i get data in Controller problem was happened.

Related

ASP.NET MVC Passing a BeginCollectionItem List's Object through AJAX with Javascript Serialize to Controller is passing null

This has been giving me some trouble for the past few days. I'm going to try to be as detailed as possible with what I want and the issue I'm having. I tried to simplify my controllers, models, etc as much as I can for the sake of the question.
Here's the flow of sequences I'm trying to get to work.
Give user a view with inputs for List<MyObject> in the main ViewModel
User can hit a button to add another row to add another object to that List of objects to post later
Hitting the button POSTs the object (in same container) through AJAX from the currently displayed list in order to repeat most of the inputs for the new row (MyObject)
Controller takes passed MyObject and maps some of the prior values to the new object
Controller passes back new MyObject and ajax appends the result html to my table
The Problem
The Ajax is passing the on-page MyObject as null (or C# doesn't know how to interpret) to my controller (step 4 above). I can't seem to get the object passed to the controller through the Ajax call.
What I've got
Models:
public class MyViewModel
{
// irrelevant properties
public List<MyObject> MyObjects { get; set; } = new List<MyObject>();
}
public class MyObject
{
public int Id { get; set; }
public string Name { get; set; }
public string AnotherProperty { get; set; }
public decimal AdditionalProperty { get; set; }
public List<MySubObject> MySubObjects { get; set; } = new List<MySubObject>();
}
public class MySubObject
{
public bool IsChecked { get; set; }
public bool Name { get; set; }
}
Controller GET:
public ActionResult Edit(int? id)
{
var viewModel = new MyViewModel();
// for list of checkboxes
var subObjects = new List<MySubObject>();
// get subobjects from db
subObjects.Add(new MySubObject {
Name = "SubObj1", IsChecked = false
});
subObjects.Add(new MySubObject {
Name = "SubObj12",
IsChecked = false
});
// populate viewModel with a blank MyObject
viewModel.MyObjects.Add(new MyObject
{
MySubObjects = subObjects
});
return (viewModel);
}
View (and AJAX call):
<table id="myObjectInputs">
#foreach (var obj in Model.MyObjects)
{
#Html.Partial("~/Areas/Admin/Views/Shared/EditorTemplates/MyObject.cshtml", obj)
}
</table>
<script>
$(document).ready(function () {
$("#myObjectInputs").on("focus", ".make-new-row", function () {
var plusButton = $(this);
var currentArea = plusButton.closest(".myobject-container");
var serializedData = currentArea.find(":input").serialize();
// add new row
$.ajax({
url: this.href,
cache: false,
type: "POST",
data: { "myObject": serializedData },
success: function (html) { $("#myObjectInputs").append(html); }
});
return false;
});
});
</script>
EditorTemplates/MyObject.cshtml:
#using HtmlHelpers.BeginCollectionItem
#model LD.Areas.Admin.Models.MyObject
<tbody class="myobject-container" style="border:solid 1px red;">
#using (Html.BeginCollectionItem("MyObjects"))
{
<tr>
<td>#Html.HiddenFor(x => x.Id)</td>
<td>#Html.EditorFor(x => x.Name)</td>
<td>#Html.EditorFor(x => x.AnotherProperty)</td>
<td>#Html.EditorFor(x => x.AdditionalProperty)</td>
<td>
#foreach (var subObj in Model.MySubObjects)
{
#Html.Partial("~/Areas/Admin/Views/Shared/EditorTemplates/MySubObject.cshtml", subObj)
}
</td>
<td>
<!-- the button that calls the function / AJAX -->
#Html.ActionLink("+", "NewMyObjectSection", null, new { #class = "make-new-row" })
</td>
</tr>
}
</tbody>
EditorTemplates/MySubObject.cshtml
#using HtmlHelpers.BeginCollectionItem
#model LD.Areas.Admin.Models.MySubObject
#using (Html.BeginCollectionItem("MySubObjects"))
{
<label>
#Html.HiddenFor(x => x.Id)
#Html.HiddenFor(x => x.Name)
#Html.EditorFor(x => x.IsChecked)#Html.LabelFor(x => x.IsChecked, Model.Name)
<text> </text>
</label>
}
ActionResult called by AJAX: (this is I'm getting null for MyObject)
public ActionResult NewMyObjectSection(MyObject myObject)
{
// take passed object values and create a new object based on myObject
var newObject = new MyObject();
return PartialView("~/Areas/Admin/Views/Shared/EditorTemplates/MyObject.cshtml", myObject);
}
What I've Tried
Some main things that stick out to me are that BeginCollectionItem attaches a GUID to make the collection items unique, for ex, when my <tablebody class="myobject-container"> is serialized, it looks like this (this is the result from my real object, Rates == MyObjects):
"Rates.index=b589808e-3e99-40f2-827c-58feaa9bebc3&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.OrganismNid=0&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.OrganismName=&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.OrganismUpdateType=New&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.IsPest=false&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.IsPreEmergent=false&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.IsPostEmergent=false&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.IsSafeOn=false&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.HasControl=false&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.HasSuppression=false&ControlTypes.index=bd9d1180-9768-4ca4-8316-fc5cbf62ca97&ControlTypes%5Bbd9d1180-9768-4ca4-8316-fc5cbf62ca97%5D.ControlTypeNid=1&ControlTypes%5Bbd9d1180-9768-4ca4-8316-fc5cbf62ca97%5D.Name=Annual&ControlTypes%5Bbd9d1180-9768-4ca4-8316-fc5cbf62ca97%5D.IsChecked=false&ControlTypes.index=0264b842-5cac-4b1a-8b79-8f9a13a26428&ControlTypes%5B0264b842-5cac-4b1a-8b79-8f9a13a26428%5D.ControlTypeNid=2&ControlTypes%5B0264b842-5cac-4b1a-8b79-8f9a13a26428%5D.Name=Biennial&ControlTypes%5B0264b842-5cac-4b1a-8b79-8f9a13a26428%5D.IsChecked=false&ControlTypes.index=6a344551-add6-4e9b-96e2-59a6fc857327&ControlTypes%5B6a344551-add6-4e9b-96e2-59a6fc857327%5D.ControlTypeNid=3&ControlTypes%5B6a344551-add6-4e9b-96e2-59a6fc857327%5D.Name=Winter%20Annual&ControlTypes%5B6a344551-add6-4e9b-96e2-59a6fc857327%5D.IsChecked=false&ControlTypes.index=91f5c6ff-402e-48ae-8f9c-1131511699a8&ControlTypes%5B91f5c6ff-402e-48ae-8f9c-1131511699a8%5D.ControlTypeNid=4&ControlTypes%5B91f5c6ff-402e-48ae-8f9c-1131511699a8%5D.Name=Perennial&ControlTypes%5B91f5c6ff-402e-48ae-8f9c-1131511699a8%5D.IsChecked=false&ControlTypes.index=3248ec07-09a8-4bf0-b99f-a518807d9636&ControlTypes%5B3248ec07-09a8-4bf0-b99f-a518807d9636%5D.ControlTypeNid=5&ControlTypes%5B3248ec07-09a8-4bf0-b99f-a518807d9636%5D.Name=Top%20Growth%20Control%20Only&ControlTypes%5B3248ec07-09a8-4bf0-b99f-a518807d9636%5D.IsChecked=false&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.BroadcastMin=&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.BroadcastMax=&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.BroadcastChemUnitTypeNid=1&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.BroadcastAreaUnitTypeNid=9&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.SpotMin=&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.SpotMax=&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.SpotChemUnitTypeNid=1&Rates%5Bb589808e-3e99-40f2-827c-58feaa9bebc3%5D.SpotFinalSolutionUnitTypeNid=1"
I'm not sure if my controller understands to bind that to my object.
I've tried other methods of passing it, such as stripping out GUIDs and extra junk from the string, passing it as a string and deserializing in C#, and others:
var serializedArray = currentArea.find(":input").serializeArray();
//https://www.regextester.com/94410
var regex = new RegExp("(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}");
var stripped = serializedData.replace(/(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}/g, '');
stripped = stripped.replace(/%5B/g, '[').replace(/%5D/g, ']');
var strung = JSON.stringify({ "modelData": serializedData });
At this point I'm at a loss. This is for a personal passion project and my lack of AJAX / JSON knowledge is really holding me back. I'm not sure what else to try. Any pointing in the right direction would be appreciated.
public ActionResult NewMyObjectSection([FromBody] MyObject myObject)
{
//myObject should be correctly populated from the request
return PartialView("~/Areas/Admin/Views/Shared/EditorTemplates/MyObject.cshtml", myObject);
}
Id Expect the item to come as a Json Object correctly passed in your request to that your myObject is populated automatically
for the request part:
var dat = {
Id:3,
Name:7,
AnotherProperty:"",
AdditionalProperty:"",
MySubObjects:[
//Create sub objects here
]
};
$.ajax({
type: "POST",
url: "youraction",
data: JSON.stringify(dat),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){alert(data);},
failure: function(errMsg) {
alert(errMsg);
}
});
})

Post knockout.js viewmodel to .Net Core (2.0) MVC Controller

Overview:
Currently, I try to create an ASP.NET Core MVC website which gets data from the server on page load. After that, the page uses knockout.js to maintain a viewmodel to update the data sent from the server (in the first step). Finally, there is a button which sends the edited data back to the server (through an AJAX request). But the corresponding value in my server method is always empty.
Current Approach:
First, there is my model class.
public class Order
{
public string Name { get; set; }
public int TemplateId { get; set; }
public decimal Price { get; set; }
public int Contingent { get; set; }
public int MaximumOrder { get; set; }
public int UserOrderCount { get; set; }
public Order() { }
public Order(SnackOffer offer)
{
Name = offer.Template.Name;
TemplateId = offer.Template.SnackTemplateId;
Price = offer.Price;
}
}
In my view I use the model class as a List (List) and load the data like this:
var model = new viewModel();
#(Json.Serialize(Model.Offers)).forEach(function (item, index) {
model.offers.push({
name: item.name,
templateId: item.templateId,
contingent: ko.observable(item.contingent),
userOrderCount: ko.observable(item.userOrderCount),
price: item.price,
maximumOrder: item.maximumOrder
});
})
The viewModel is defined like this (shortend for readability):
function viewModel() {
var self = this;
self.offers = ko.observableArray();
}
Now after someone hits the mentioned update button I call this javascript function:
self.ConfirmOrder = function () {
var data = ko.toJSON(self.offers);
$('#overlay').css('display', 'block');
$.ajax({
type: 'post',
url: '/Snack/ConfirmOrder',
data: data,
contentType: 'application/json; charset=utf-8',
success: function (result) {
$('#overlay').css('display', 'none');
},
error: function (result) {
console.log(result);
$('#overlay').css('display', 'none');
}
});
}
Here you can see that I use the ko.toJSON method to convert the observableArray to a JSON String and use this string as the data argument for the ajax post.
The ConfirmOrder method in the MVC Controller looks like this currently:
[HttpPost]
public void ConfirmOrder(List<OrderSnackViewModel.Order> offers)
{
foreach (var item in offers)
{
_logger.LogInformation(item.Name);
}
}
There is no logic yet cause the offers list is created (so not null) but the count of list items is always 0.
In a concret example this is the JSON string I receive from the server while load the view:
[{"name":"Test","templateId":1,"price":1.94,"contingent":4,"maximumOrder":7,"userOrderCount":0},{"name":"Test 1","templateId":2,"price":1.50,"contingent":30,"maximumOrder":7,"userOrderCount":0}]
And this is the string i produce with the ajax call:
[{"name":"Test","templateId":1,"contingent":4,"userOrderCount":0,"price":1.94,"maximumOrder":7},{"name":"Test 1","templateId":2,"contingent":30,"userOrderCount":0,"price":1.5,"maximumOrder":7}]
What have I tried already:
I have tried to use FromBody in my MVC Controller
I have tried to prefix the JSON output with the name offer so my controller method can map the JSON string items to the object. (e.g. data = '{ "offers":' + data + '}'; )
I have tried to rename the Properties of my model to match exactly the JSON names. So I renamed Name to name and Contingent to contingent and so on.
I have tried to use an array instead of the List in the MVC controller action
Is there a master somewhere which can help me with this problem?
(If you need some more information please do not hesitate to ask)
Thanks to the input of #adiga I have found the solutions for (my) error.
[HttpPost]
public JsonResult ConfirmOrder([FromBody]List<Order> offers)
{
_logger.LogInformation("COUNT -> " + offers.Count());
foreach (var item in offers)
{
_logger.LogInformation(item.Name);
}
}
This is the working solution. I thought I already have tried it but maybe I have forgoten the content-type for the ajax post.
var data = ko.toJSON(self.offers);
$('#overlay').css('display', 'block');
$.ajax({
type: 'post',
url: '/Snack/ConfirmOrder',
data: data,
contentType: 'application/json; charset=utf-8',
success: function (result) {
//location.reload();
$('#overlay').css('display', 'none');
},
error: function (result) {
console.log(result);
$('#overlay').css('display', 'none');
}
});
Thanks again for all responses!

How to deserialize multiple JSON objects in C#?

I'm passing multiple JSON objects from my frontend to a C# backend - how can I deserialize them into C# classes so they can be used later on in my application? Before I go any farther, I am tied to using the JS FormData object, contentType: false, and processData: false, because I also need to pass files via this AJAX call; that is completely unrelated to this question. Here's my code so far:
Frontend - function is called when a submit button is pressed
submitData: function () {
var formCollection = this.appModel.get('formCollection').models;
var formData = new FormData();
var formJson = [];
$.each(formCollection, function (index, form) {
var tempJson = {};
if (form) {
tempJson['id'] = form.get('id');
tempJson['number'] = form.get('number');
tempJson['name'] = form.get('name');
tempJson['attachments'] = form.get('attachments');
formJson.push(tempJson);
}
});
console.log(JSON.stringify(formJson));
formData.append('formJson', JSON.stringify(formJson));
$.ajax({
type: "POST",
url: '/NMISProduct/Test',
contentType: false,
processData: false,
data: formData,
success: function (result) {
console.log(result);
}
});
}
JSON.stringified data that's being passed
[{"id":1,"number":null,"name":"Investment Portfolio Statement","attachments":null},{"id":2,"number":"61-0227","name":"WMC Signature Portfolio Agreement","attachments":null},{"id":3,"number":"61-1126","name":"WMC Signature Choice Agreement","attachments":null},{"id":4,"number":"61-1162","name":"WMC Signature Annuities Agreement","attachments":null},{"id":5,"number":"61-1205","name":"WMC Signature Managed Accounts Client Agreement","attachments":null}]
C# MVC 5 Backend
[HttpPost]
public async Task<JsonResult> Test()
{
Debug.WriteLine(Request.Params["formJson"]);
var forms = JsonConvert.DeserializeObject<Form>(Request.Params["formJson"]);
Debug.WriteLine(forms);
try
{
var srNumber = GetSRNumber();
foreach (string file in Request.Files)
{
var fileContent = Request.Files[file];
Debug.WriteLine(ReadFileInputStream(fileContent));
if (fileContent != null && fileContent.ContentLength > 0)
{
// get a stream
var stream = fileContent.InputStream;
// and optionally write the file to disk
//var fileName = Path.GetFileName(file);
var fileName = fileContent.FileName;
var path = Path.Combine(Server.MapPath("~/App_Data/"), fileName);
using (var fileStream = System.IO.File.Create(path))
{
stream.CopyTo(fileStream);
}
}
}
}
catch (Exception)
{
return Json("Upload failed");
}
return Json("File uploaded successfully");
}
public class Form
{
public int id { get; set; }
public string number { get; set; }
public string name { get; set; }
public Form attachments { get; set; }
public byte[] fileAsBytes { get; set; }
}
I've done my research and found several Stackoverflow questions that show how to serialize one JSON object into one C# class - however, I need to serialize multiple JSON objects into a List<Form>. How can I do this? What am I doing wrong in the posted code?
You're trying to deserialize to a single form here:
var forms = JsonConvert.DeserializeObject<Form>(Request.Params["formJson"]);
Just change it to:
var forms = JsonConvert.DeserializeObject<List<Form>>(Request.Params["formJson"]);
You should then be able to use forms in a normal way - iterating over it, taking a count etc.
[HttpPost]
public async Task<JsonResult> Test(List<Form> forms)
{
// your code here
}
And put your JS code
formJson.push(tempJson);
inside the
if (form)

My controller don't receive the IDs of an AJAX request

I have a JavaScript function that uses AJAX request to send data to my controller on asp.net MVC. Look:
function verCarrinho() {
$.ajax({
type: "POST",
url: "/Produto/Carrinho",
data: { "carrinho": carrinho },
success: function (e) {
}
});
}
Where carrinho is an array with two properties. One of these properties is an ID that I need to send to my controller to use EF to make a query on my data base.
My ActioNResult on controller:
[HttpPost]
public ActionResult Carrinho(List<Carrinho> carrinho)
{
var ids = carrinho.Select(s => s.idLivro).ToList();
var resultado = db.Produtos.Where(w => ids.Contains(w.idProduto));
return PartialView("_Carrinho", resultado);
}
The problem is: my variable "resultado" stay null! The AJAX is not sending the IDs. If I put a breakpoint on resultado I can see that AJAX send the objects, but I can't see the IDs.
I have a class same type of my parameter:
public class Carrinho
{
public int idLivro;
public int qtdProduto;
}
I don't know if I could be clear, but I hope you can help.
Thank you.
you need to data: JSON.stringify({ "carrinho": carrinho }) and also add contentType: 'application/json; charset=utf-8', to ajax call.
Javascript Object Literal Syntax !== JSON.
You need to JSON.stringify() your data object in your ajax request.
I changed my code based on a friend's code and it works. It's look like this:
namespace WebAppImaginario.Models
{
public class ItemCarrinho
{
public int idLivro { get; set; }
[DisplayName("Quantidade do Produto")]
public int qtdProduto { get; set; }
[DisplayName("Nome do Produto")]
public string nomeProduto { get; set; }
[DisplayName("Descrição do Produto")]
public string descProduto { get; set; }
[DisplayName("Preço do Produto")]
public decimal precProduto { get; set; }
[DisplayName("Desconto da Promoção")]
public decimal descontoPromocao { get; set; }
[DisplayName("Imagem")]
public byte[] imagem { get; set; }
}
}
Controller:
[HttpPost]
public ActionResult Carrinho(string hidCarrinho)
{
List<ItemCarrinho> listaCarrinho = new List<ItemCarrinho>();
if (hidCarrinho != null)
{
var itens = JsonConvert.DeserializeObject<List<ItemCarrinho>>(hidCarrinho);
foreach (var item in itens)
{
var qtd = int.Parse(new string(item.qtdProduto.ToString().Where(char.IsDigit).ToArray()));
if (qtd > 0)
{
var idLivroNumerico = int.Parse(new string(item.idLivro.ToString().Where(char.IsDigit).ToArray()));
var resultado = db.Produtos.Where(m => m.idProduto == idLivroNumerico).FirstOrDefault();
ItemCarrinho prod = new ItemCarrinho();
prod.idLivro = idLivroNumerico;
prod.qtdProduto = qtd;
prod.nomeProduto = resultado.nomeProduto;
prod.descProduto = resultado.descProduto;
prod.precProduto = resultado.precProduto;
prod.descontoPromocao = resultado.descontoPromocao;
prod.imagem = resultado.imagem;
listaCarrinho.Add(prod);
}
}
}
return View(listaCarrinho);
}
JavaScript:
function setValueEnviar() {
$("#hiddenInputContainer").empty();
for (var i = 0; i < carrinho.length; i++) {
var newInput = document.createElement('input');
newInput.type = "hidden";
newInput.value = JSON.stringify(carrinho[i]);
newInput.name = 'data';
$("#hiddenInputContainer").append(newInput);
}
}
$('#formCarrinho').submit(function (e) {
e.preventDefault();
$('#hidCarrinho').val(JSON.stringify(carrinho));
document.formCarrinho.submit();
})
Those IDs are a form on my page and hidden input. I don't know if it is clear, but it works to me.
Thank you for all support.
Syntax like data: { "carrinho": carrinho } can work, $.ajax does accept a PlainObject as data (see http://api.jquery.com/jquery.ajax/).
Your problem is that your variable carrinho is not conforming to the requirements of a PlainObject.
The PlainObject type is a JavaScript object containing zero or more key-value pairs
http://api.jquery.com/Types/#PlainObject
Depending on what carrinho is, you may have success with stringify as an alternative:
function verCarrinho() {
$.ajax({
type: "POST",
url: "/Produto/Carrinho",
data: JSON.stringify({ "carrinho": carrinho }),
success: function (e) {
}
});
}

Posting/Binding multiple forms on backend ASP.NET MVC (MEF)

We are trying to send multiple forms with one Ajax (jQuery) Call to an ASP application.
We use the following jQuery code:
var formContainer = {
Form1 : form1.serialize(),
Form2 : form2.serialize()
}
$.ajax({
type: "POST",
url: '#Url.Action("CreateModel", "Controller")',
data: formContainer,
success: function (result) { }
});
On the server we receive the following in the Request.Form property:
Key : Value
Form1 : All serialized form elements for Form1
Form2 : All serialized form elements for Form2
Normally we use the following method so ASP is automaticly creating the object with the right property value:
public ActionResult CreateModel(ClassForForm1 obj)
But because the two forms are send together the modelbinder cannot bind and build the class.
So for this action we want the modelbuilder to use the values in Request.Form["Form1"].
We can't use a custom modelbinder, because we use an extern library (DevExpress ,they wrote an own implementation above this).
We are using the MEF framework to add functionalities (these functionalities are added as forms on the view). For this reason we do not know what too expect on the backend. So writing a wrapper ViewModel is not acceptable.
The functionality for proccessing the other forms data will be handeled inside other modules.
Any solutions are welcome!
Thanks in advance.
This is typically done using a combined view model. Otherwise, you would need to manually parse the request parameters. Here is a fiddle showing how to combine the data from multiple forms.
$(function() {
$('button').click(function(e) {
var form1 = $('#form1');
var form2 = $('#form2');
$.ajax({
type: "POST",
url: '/echo/html/',
data: form1.serialize()+"&"+form2.serialize(),
success: function (result) {
alert(result);
}
});
});
});
On the server, your view model would require:
public class IndexViewModel {
// properties from form1
public string first { get; set; }
// properties from form2
public string last { get; set; }
}
public class First {
public string first { get; set; }
}
public class Last {
public string last { get; set; }
}
And your action signature:
[HttpPost]
public ActionResult Index(IndexViewModel model) {
var firstModel = (new First()).CloneMatching(model);
var lastModel = (new Last()).CloneMatching(model);
return RedirectToAction("Thanks");
}
See Best way to clone properties of disparate objects for the CloneMatching extension method.
If you create you javascript object like this:
var formContainer = { obj : {
Form1 : form1.serialize(),
Form2 : form2.serialize()
}
}
The controller should match it up with the name 'obj' you created in the javascript with the 'obj' in your method....
public ActionResult CreateModel(ClassForForm1 obj)
My previous sample worked just because my class has name and value props. I'm realy sorry for that. But now you can see working DEMO
JS
function mapForm(form)
{
var result = {};
$.map($(form).serializeArray(),
function(el){
mapFormProperty(result, el);
});
return result;
}
function mapFormProperty(form, property)
{
form[property.name] = property.value;
}
$('.submit').click(function(){
var form1 = mapForm($('#form1'));
var form2 = mapForm($('#form2'));
var formContainer = {
'Form1': form1,
'Form2': form2};
$.ajax({
type: "POST",
url: '#Url.Action("CreateModel", "Controller")',
data: JSON.stringify(formContainer),
success: function (result) { }
});
Operations with forms and form container should give you next json string
"{"Form1":{"Prop1":"Value1","Prop2":"Value2"},"Form2":{"Prop1":"Value1","Prop2":"Value2"}}"
And your model binder will be able solve this, if you change your action signature
Action
public ActionResult CreateModel(ClassForForm1 Form1) //argument name must be equal to data property
//but not equal to class name
And it should work. it works in my test sample

Categories