I wanted to post a Javascript Array to a WebAPI.
I have my Javascript Array like:
var checkedGroups = [];
var checkedStaff = [];
$.each(items, function () {
if (this.checked) {
type = dataAdapter.records[this.id - 1].VALUETYPE;
if (type == 'Staff') {
checkedStaff[checkedStaff.length] = this.value;
} else {
checkedGroups[checkedGroups.length] = this.value;
}
}
});
I am then sending this to my WebAPI using this:
data: { staff: JSON.stringify(checkedStaff) };
My WebAPI Controller is then like:
public HttpResponseMessage Post([FromBody] formData data)
{
string string_group = String.Join(",", data.group);
string string_staff = String.Join(",", data.staff);
}
and my formData class is this:
public class formData
{
public Array group { get; set; }
public Array staff { get; set; }
}
As per above, I would like to split the array out to make a comma delimerated string.
But string_staff variable on the server side is just an empty string and my JSON data was this:
staff: "["1"]"
group: ""
I do not want to use key/value types in the array either.
Any idea's?
Change checkedGroups and checkedStaff variables to object literals. There's not really such a thing as an associative array in Javascript the way you're trying to set it.
var checkedGroups = {};
var checkedStaff = {};
$.each(items, function () {
if (this.checked) {
type = dataAdapter.records[this.id - 1].VALUETYPE;
if (type == 'Staff') {
checkedStaff[checkedStaff.length] = this.value;
} else {
checkedGroups[checkedGroups.length] = this.value;
}
}
});
You could keep them as arrays if you do:
checkedStaff.push(this.value);
Generally, you should use jQuery ajax function $.ajax({ ... }) to post to WebAPI controller. I have found this method works the best:
function postJSON(data)
{
return $.ajax({
url: '/api/xyz',
type: 'POST',
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8" // must have this option set
});
}
function doSomethingElse() {
postJSON({ staff: checkedStaff, group: checkedGroup })
.done(function(response) { ... });
}
Related
I have a javascript function that is creating a model that includes an array of objects and sending that data to my MVC controller with an AJAX POST request. For some reason, it seems that there is a limit on the size of that array that can be passed to the controller though, which though experimentation, seems to be between 450 and 500 objects in my case. Once it's larger than that threshold, the controller will just receive a null value. Is there some configuration or workaround that can be done to remove or work around this limitation?
I've already tried several web.config based "solutions" that a lot of people have proposed on similar SO questions to no avail (I think those may be applicable only for .Net Framework's version of ASP.NET, not .NET Core).
Javascript:
var i = 0;
$("#SupplierNumber option").each(function () {
var supplierNumber = {};
supplierNumber.Value = $(this).val();
supplierNumber.text = $(this).val();
supplierNumbers.push(supplierNumber);
//Below limits max size for testing
i = i + 1;
if (i > 450) {
return false;
}
});
//Other non-array values gathered here
var model = {
"SupplierNumbers": supplierNumbers,
//... other non-array values added to model
}
$.ajax({
type: "POST",
url: "/Administration/TestPost",
data: model,
dataType: "json",
success: function (data) {
alert("Finished");
}
});
Controller:
[HttpPost]
public async Task<IActionResult> TestPost(TestViewModel model)
{
//model is null here when array is > 500 in size
return Json(new { success = true });
}
Try this before you use JSON.stringify!
I had exactly the same problem. All I needed to do was the following:
In my Startup.cs I added the following lines in ConfigureServices:
services.Configure<FormOptions>(options =>
{
options.ValueCountLimit = int.MaxValue;
options.ValueLengthLimit = int.MaxValue;
});
Here is two solutions:
First demo,use json type data,we usually use this way to pass array in ajax(pass json type data,need to use contentType: 'application/json' in ajax and use [FromBody] in action):
IndexViewModel:
public class IndexViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller:
[HttpGet]
public IActionResult TestAjax() {
return View();
}
[HttpPost]
public IActionResult TestAjaxWithJsonData([FromBody]List<IndexViewModel> l) {
return Ok();
}
View:
<button onclick="postdata1()">submit(jsondata)</button>
#section scripts{
<script type="text/javascript">
function postdata1() {
var a = [];
for (var i = 0; i < 500; i++) {
var indexViewModel = {};
indexViewModel.Id = i;
indexViewModel.Name = "name" + i;
a.push(indexViewModel);
}
var data = JSON.stringify(a);
$.ajax({
type: "POST",
url: 'TestAjaxWithJsonData',
data: data,
contentType: 'application/json'
}).done(function (data) {
});
}
</script>
}
result:
Second demo,use FormData:
Controller:
[HttpPost]
public IActionResult TestAjaxWithFormdata(List<IndexViewModel> l)
{
return Ok();
}
View:
<button onclick="postdata2()">submit(formdata)</button>
#section scripts{
<script type="text/javascript">
function postdata2() {
var formdata = new FormData();
for (var i = 0; i < 500; i++) {
formdata.append("l[" + i + "].Id", i);
formdata.append("l[" + i + "].Name", "name" + i);
}
$.ajax({
type: "POST",
url: 'TestAjaxWithFormdata',
cache: false,
contentType: false,
processData: false,
data: formdata,
}).done(function (data) {
});
}
</script>
}
result:
I dont know what is the exact problem but you can try this solution. Try to pass data as a sting into action after that Deserialize tht string to object.
var model = {
"SupplierNumbers": supplierNumbers,
//... other non-array values added to model
}
$.ajax({
type: "POST",
url: "/Administration/TestPost",
data: {"data":JSON.stringify(model)},
dataType: "json",
success: function (data) {
alert("Finished");
}
});
on controller side you can Deserilize this string to model.
[HttpPost]
public async Task<IActionResult> TestPost(string data)
{
TestViewModel model=DeserializeObject<TestViewModel>(data);
return Json(new { success = true });
}
We need to set the value count limit and length.
Please Add below code in startup.cs --- It is working for me
services.AddMvc(options =>
{
options.MaxModelBindingCollectionSize = 100000;
});
services.Configure<FormOptions>(options =>
{
options.ValueCountLimit = int.MaxValue;
options.ValueLengthLimit = int.MaxValue;
options.MultipartHeadersLengthLimit = int.MaxValue;
});
After some more searching, I was able to figure out that this is a configuration issue within ASP.NET Core. By default, the max number of values in a complex model that can be bound is 1024. Adding the option below in the ConfigureServices method of the Startup class will allow you to increase this limit to whatever you need (MSDN).
services.AddMvc(options =>
{
options.MaxModelBindingCollectionSize = 100000;
})
Also, something else that I found that people might find useful when facing this problem, but with a form submit action, is the below option that goes in the same method mentioned above (source).
services.Configure<FormOptions>(options => options.ValueCountLimit = 100000);
Array of objects after stringifying is not passed to controller action and the parameter of action (the model) is null.
I have tried many solutions given to this problem in StackOverflow but none of these solution solved my problem. I provided the links which I tried:
Pass array to mvc Action via AJAX
pass array in javascript object to mvc controller
Here is my code
JavaScript Code
$("#FormSubmit").click(function () {
var datalist = [];
$("#MarksTable tbody tr").each(function () {
var obj = {};
obj.StudentID = 1;
obj.ExamTimeTableID = 1;
obj.ClassActivity = $(this).find("td:eq(5) input").val();
obj.IsPresent = $(this).find("td:eq(7) input").val();
obj.Assignment = $(this).find("td:eq(6) input").val();
obj.MidTerm = $(this).find("td:eq(3) input").val();
obj.Final = $(this).find("td:eq(4) input").val();
datalist.push(obj);
});
$.ajax({
url: "#Url.Action("InsertData", "Examination")",
type: "POST",
cache: false,
contentType: "application/json;charset=utf-8",
dataType: "json",
data: JSON.stringify(datalist),
success: function (result) {
alert(result);
},
error: function (errormessage) {
alert(errormessage.responseText);
}
});
});
Action of Controller:
[HttpPost]
public JsonResult InsertData([FromBody] List<StudentMarksList> obj)
{
DynamicParameters param = new DynamicParameters();
.
.
.
return Json(param.Get<string>("msg"));
}
The Model:
public class StudentMarksList
{
public int StudentID { get; set; }
public int ExamTimeTableID { get; set; }
public int ClassActivity { get; set; }
public int IsPresent { get; set; }
public int Assignment { get; set; }
public int MidTerm { get; set; }
public int Final { get; set; }
}
Request Payload:
[,…]
0: {StudentID: 1, ExamTimeTableID: 1, ClassActivity: 3, IsPresent: 0, Assignment: 2, MidTerm: 5, Final: 4}
Assignment: 2
ClassActivity: 3
ExamTimeTableID: 1
Final: 4
IsPresent: 0
MidTerm: 5
StudentID: 1
Request Payload source:
[{"StudentID":1,"ExamTimeTableID":1,"ClassActivity":3,"IsPresent":0,"Assignment":2,"MidTerm":5,"Final":4}]
The obj should contains the passed objects but it is null.
Any Help???
[Edit]
Change the js as below:
function toInt(str){
var i = parseInt(str);
return i ? i : 0;
}
$("#MarksTable tbody tr").each(function () {
var obj = {};
obj.StudentID = 1;
obj.ExamTimeTableID = 1;
obj.ClassActivity = toInt( $(this).find("td:eq(5) input").val());
obj.IsPresent =toInt( $(this).find("td:eq(7) input").val());
obj.Assignment = toInt( $(this).find("td:eq(6) input").val());
obj.MidTerm =toInt( $(this).find("td:eq(3) input").val());
obj.Final = toInt( $(this).find("td:eq(4) input").val());
datalist.push(obj);
});
This will make sure the empty input to 0 instead of null.
That's because on your server side you're declaring the ClassActivity/ClassActivity/Assignment/... as int type but your js send all them as string. For example, the Payload sent to server will be something like:
[{"StudentID":1,"ExamTimeTableID":1,"ClassActivity":"3","Assignment":"aa","MidTerm":"333333333","Final":"3333"},{"StudentID":1,"ExamTimeTableID":1,"ClassActivity":"","Assignment":"s","MidTerm":"2","Final":"1"},{"StudentID":1,"ExamTimeTableID":1,"ClassActivity":"3","Assignment":"","MidTerm":"2","Final":"1"}]
Please either change the property type or convert the $(this).find("td:eq(7) input").val() result (a string) to int/bool/... type before sending them.
You can try this also.
cshtml page you need to add one form tag like eg.
<div style="display:none;">
<form id="FormPost"></form>
</div>
Jquery Code
$("#FormSubmit").click(function () {
$("#FormPost").html('');
$("#MarksTable tbody tr").each(function (index,elem) {
addHidden("StudentID["+index+"]","1");
addHidden("ExamTimeTableID["+index+"]","1");
addHidden("ClassActivity["+index+"]",$(this).find("td:eq(5) input").val());
addHidden("IsPresent["+index+"]",$(this).find("td:eq(7) input").val());
addHidden("Assignment["+index+"]",$(this).find("td:eq(6) input").val());
addHidden("MidTerm["+index+"]",$(this).find("td:eq(3) input").val());
addHidden("Final["+index+"]",$(this).find("td:eq(4) input").val());
});
$.ajax({
url: "#Url.Action("InsertData", "Examination")",
type: "POST",
cache: false,
contentType: "application/json;charset=utf-8",
dataType: "json",
data: $("#FormPost").serialize(),
success: function (result) {
alert(result);
},
error: function (errormessage) {
alert(errormessage.responseText);
}
});
});
function addHidden(key, value) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = key;
input.value = value;
$("#FormPost").appendChild(input);
}
Action of Controller:
[HttpPost]
public JsonResult InsertData(List<StudentMarksList> obj)
{
DynamicParameters param = new DynamicParameters();
.
.
.
return Json(param.Get<string>("msg"));
}
That could be dynamic value of one of property in object below is not a number, it contains some alphabet characters.
var obj = {};
obj.StudentID = 1;
obj.ExamTimeTableID = 1;
obj.ClassActivity = $(this).find("td:eq(5) input").val();//this value could be not a number, ex: 'abc' text
obj.IsPresent = $(this).find("td:eq(7) input").val();
obj.Assignment = $(this).find("td:eq(6) input").val();
obj.MidTerm = $(this).find("td:eq(3) input").val();
obj.Final = $(this).find("td:eq(4) input").val();
It will be reason that Asp.Net cannot deserialize your action parameter item to object of StudentMarksList.
If above is not the root cause, you can follow this question to log out serialization errors to have further investigation.
Simply add this property to your ajax call:
traditional:true,
such that your ajax call looks like this at the end
$.ajax({
url: "#Url.Action("InsertData", "Examination")",
type: "POST",
cache: false,
traditional:true,
contentType: "application/json;charset=utf-8",
dataType: "json",
data: JSON.stringify(datalist),
success: function (result) {
alert(result);
},
error: function (errormessage) {
alert(errormessage.responseText);
}
});
Happy coding. Hope it helps someone just as it helped me.
I am wanting to pass a dictionary of type <int,int> to my controller via an Ajax post.
The main reason here is the post may have between 1-3 key value pairs here (none of these values are known at compile time) and in the future it may go up to 5.
Also in the post I have to pass in some other data, such as Id and name, which all works as normal.
How would I construct this dictionay in the javascript then send it via the JQuery post and finally receive it on the controller to process?
Edit 2:
I have decided to just solve this with a post for each value instead of trying to pass a dictionary.
EDIT:
Here is my source for the function so you can see what I am trying:
function BindAddMenuItem() {
$(".AddMenuItem").click(function (e) {
e.preventDefault();
//get header id from link by removing addmenuitem from this.id
var currentId = $(this).attr("id").replace("AddMenuItem", "");
//get itemnumber, itemname, itemdetails from textboxes with same header id
var restaurantId = jQuery.trim($("#RestaurantId").val());
var itemNumber = jQuery.trim($("#ItemNumber" + currentId).val());
var itemName = jQuery.trim($("#ItemName" + currentId).val());
var itemDetails = jQuery.trim($("#ItemDetails" + currentId).val());
var costs = new Object();
//select all textboxes with class "Header" + currentId
$(".Header" + currentId).each(function (i) {
var optionId = $(this).attr("id").replace("Option", "");
costs[optionId] = $(this).val();
});
$.ajax(
{
type: "POST",
url: "/Menu/AddMenuItem",
data: "reastaurantId=" + restaurantId + "&menuHeaderId=" + currentId + "&itemNumber=" + itemNumber + "&itemName=" + itemName + "&itemDetails=" + itemDetails + "&costs=" + costs,
dataType: "html",
success: function (result) {
var domElement = $(result);
$("#MenuContainer").replaceWith(domElement);
var newNum = parseInt(itemNumber) + 1;
$("#ItemNumber" + currentId).val(newNum);
BindAllBehaviours();
}
});
});
}
Something like (javascript)
dict = new Object();
dict['12'] = 5;
dict['13'] = 6;
dict['1000'] = 21;
dict['9'] = 13;
dict['13'] = 48;
$.post('/client.mvc/mypostaction/', { myDictionary: dict });
You can then post the dict object to your controller using a Dictionary<int, int> as property type.
ActionResult MyPostAction(Dictionary<string, int> myDictionary)
edit from author's code second time:
The following works for me, when having a Dictionary<string, int> kvPairs. <int, int> isn't going to work after all.
Make your post like:
var dict = new Object();
dict['13'] = 9;
dict['14'] = 10;
dict['2'] = 5;
$.post('controller.mvc/Test', { 'kvPairs': dict }, function(obj) { $('#output').html(obj.Count); });
JavaScript object / dictionary has to be passed as a list of key-value pairs to ASP.NET MVC controller when Dictionary<TKey, TValue> is expected. Example:
If you have a dictionary like this:
public Dictionary<string, decimal?> SomeMapping { get; set; }
then you have to use something like this in your JavaScript:
var sourceMapping = { a: 1, b: 1.5, c: null };
var SomeMapping = [];
for (var key in sourceMapping) {
if (sourceMapping.hasOwnProperty(key)) {
SomeMapping.push({ Key: key, Value: sourceMapping[key] });
}
}
I've used this approach in asynchronous POST request (sent using jQuery) that had content type set to 'application/json' (this may or may not be important in your case).
Client (JavaScript):
var dict = new Object();
dict.Key1 = "Value1"
dict.Key2 = "Value2"
$.post('/YourController/YourAction/', dict);
NOTE: The "dict" objects gets serialized behind the scenes before being sent to your action.
Server:
public ActionResult YourAction()
{
string postData = string.Empty;
using (StreamReader sr = new StreamReader(Request.InputStream))
{
postData = sr.ReadToEnd();
}
//Load post data into JObject (Newtonsoft.Json)
JObject o = JObject.Parse(postData);
//Extract each key/val
string val1 = (string)o["Key1"];
//Do whatever....
}
None of these worked for me except for mczers, but he doesn't show all the steps, and makes it difficult when you're trying to remember how you set up an ajax request. So I wanted to put everything that actually just works. First, in JavaScript:
var validDict = new Array();
validDict[0] = { key: 1, value: 4 }
validDict[1] = { key: 42, value: 5}
var path = "#Url.Action("ControllerName", "ActionName")";
$.ajax({
url: path,
type: "POST",
data: JSON.stringify(validDict),
contentType: "application/json; charset=utf-8",
async:false,
success: function(status, xhr)
{
alert(status);
},
error: function(xhr, status, error)
{
alert(error);
}});
Then in your controller:
[HttpPost]
public ActionResult ActionName(Dictionary<int, int> validDict)
{
// doStuff();
return Content("Success");
}
A dictionary of the kind IDictionary<string, string> on server side can be posted from javascript like
{"Key1": "Value1", "Key2": "Value2"}
on the Server Side in ASP.NET Web API
[HttpPost]
public IHttpActionResult([FromBody]IDictionary<string, string> requestParam){
}
Above example is for an Http POST with the Json data in the Body
For passing a Dictionary I found the following working answer:
submitting-a-dictionary-to-an-asp-net-mvc-action
#model WebApplication3.Controllers.ExampleViewModel #{ ViewBag.Title = "New";
var first = Guid.NewGuid(); var second = Guid.NewGuid(); }
<h2>New</h2>
#using (Html.BeginForm(new { action = "create", controller = "home" })) {
foreach (var kvp in Model.Values) {
<p>
<input type="text" name="Model.Values[#first].Key" value="#kvp.Key" />
<input type="text" name="Model.Values[#first].Value" value="#kvp.Value" />
<input type="hidden" name="Model.Values.Index" value="#first" />
</p>
}
you have to generate A Guid for the dictionary index, and you have to create 3 inputs, one for the Key, one for the Value and one for the Index of the Dictionary
Also I have submited using Jquery with the following:
$('form#frmFormId').submit(function (e) {
e.preventDefault();
var formData = new FormData(this);
//debugger;
$('#cover-spin').show(100);
$.ajax({
type: 'POST',
url: $(this).attr('action'),
data: formData,
processData: false,
contentType: false
}
);
return false;
});
I have a Asp.net MVC program in which i want to get a list from the View using Javascript and pass that list to the controller. I want to the variables in the list to be string type except for one to be int32.
The problem is the list is either empty or does not pass.
I tried to use stringify but it doesn't fill the requirments.
Here is the code from the javascript part:
$('#AddColumn').click(function () {
var nodeURL = document.getElementById("IDHolder").innerHTML;
var nodeConfig= nodeURL+".CONFIG";
var nodeAdd=nodeURL+".CONFIG.AddColumn";
var nodeName = $("#ColumnName").val();
var nodeType = $("#ColumnType").data("kendoComboBox").value();
var ListNodedet = [nodeName, nodeType];
var Listmet = [nodeConfig, nodeAdd];
var ListNodeDetails = JSON.stringify(ListNodedet);
var ListMethod = JSON.stringify(Listmet);
var select = 1;
var url = "/Configuration/CallMethod";
$.get(url, { ListNodeDetails:ListNodeDetails, ListMethod:ListMethod }, function (data) {
$("#Data2").html(data);
});
})
The C# code for the controller were it calls another method in models:
public bool CallMethod(List<Variant> ListNodeDetails, List <string> ListMethod)
{
var AddMethod = RxMUaClient.CallMethod(ListNodeDetails, ListMethod, "127.0.0.1:48030");
return AddMethod;
}
The Model:
public static bool CallMethod(List<Variant> ListNodeDetails, List<string> ListMethod, string iPAddress)
{
var serverInstance = GetServerInstance(iPAddress);
if (serverInstance == null)
return false;
return serverInstance.CallMethod(ListNodeDetails, ListMethod);
}
The service model
public bool CallMethod(List<Variant> ListNodeDetails, List<string> ListMethod)
{
try
{
if (_mSession == null)
{
return false;
}
NodeId objectID = NodeId.Parse(ListMethod[0]);
NodeId Methodtype = NodeId.Parse(ListMethod[1]); ;
List<Variant> inputArguments = ListNodeDetails;
List<StatusCode> inputArgumentErrors = null;
List<Variant> outputArguments = null;
StatusCode error = _mSession.Call(
objectID,
Methodtype,
inputArguments,
new RequestSettings() { OperationTimeout = 10000 },
out inputArgumentErrors,
out outputArguments);
if (StatusCode.IsBad(error))
{
Console.Write("Server returned an error while calling method: " + error.ToString());
return false;
}
return true;
}
catch (Exception exception)
{
Console.WriteLine(exception.ToString());
return false;
}
}
At the end it calls some functions using OPC UA to add data.
I have changed it to be ajax function and it works well but only with one list form the lists passed to the method!
I dont know if this is because i read values from kendo box and text box, and they are different types but i tried to stringfy it and it still does not work. On the console both lists are out as strings. So still got a problem with passing the first List "ListNodeDetails"!
$('#AddColumn').click(function () {
var nodeURL = document.getElementById("IDHolder").innerHTML;
var nodeConfig= nodeURL+".CONFIG";
var nodeAdd=nodeURL+".CONFIG.AddColumn";
var nodeName = $("#ColumnName").val().toString();
var nodeType = $("#ColumnType").data("kendoComboBox").value().toString();
var ListNodedet = [nodeName, nodeType];
var Listmet = [nodeConfig, nodeAdd];
var params = {
ListNodeDetails: ListNodedet,
ListMethod: Listmet
};
var url = "/Configuration/CallMethod";
console.log(params); // added sanity check to make sure data is correctly passed
var temp = {
url: "/Configuration/CallMethod",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(params),
success: function (params) {
window.location.replace(params.redirect);
}
};
$.ajax(temp);
})
I have a generic dispatcher that takes in parameters and then make $.ajax()
As you can see, I am looping through the parameters to build the data.
function dispatch(controller, action, param1, param2,...) {
var args = '', pg = 1, id = '';
var l = arguments.length;
var data = {};
for (var i = 2; i < arguments.length; i += 2) {
data[arguments[i]] = arguments[i + 1];
}
$.ajax({
type: "POST",
url: "/" + (controller + "/" + action,
data: data,
dataType: "json",
success: function (res) {
alert('success');
},
error: function (xhr, status, error) {
alert('error!');
}
});
}
This is how I call:
dispatch("XYZ", "AddGuests", "id", 10, "name", "Bob");
Everything works as expected and I get all parameters back in my MVC 3 controllers.
Now I need to pass multidimentional associative array as parameter to my controller.
I want to use the single generic dispatcher I use for other calls.
But somehow I am getting null for the associative array parameter.
Basically I want to post a guests array to my controller's List parameter.
Code to prepare the associative array data:
var guest = {};
var guests = [];
for(var i=0;i<2;i++){
var name = GetName();
var email = GetEmail();
guest = { 'Email': email, 'Name': name };
guests.push(guest);
}
End of the loop would give me, say:
{
{'Email':"bob#zyz.com", 'Name':"Bob"},
{'Email':"tom#zyz.com", 'Name':"Tom"}
}
This is the new call to the dispatcher:
dispatch("XYZ", "AddGuests", "id", 10, "guests", JSON.stringify(guests));
This is my controller:
[HttpPost]
public ActionResult AddGuests(string id, List<SelectedGuest> guests){
//save guests
}
[Serializable]
public class SelectedGuest
{
public string Email { get; set; }
public string Name { get; set; }
}
When I look at httpfox I see correct values posted:
id 10
guests [{"Email":"bob#zyz.com","Name":"Bob"},{"Email":"tom#zyz.com","Name":"Tom"}]
If I do this, I get the guest passed correctly to my controller:
But this limits me to pass just the guests array not other parameters.
data = JSON.stringify(guests);
What I am doing wrong? Thanks for reading.
If using JSON.stringify(guests) works, why not combine it into another JSON object with your other parameters that don't need stringification?
data = { "id": 10, "Guests": JSON.stringify(guests) };
Alternatively, you could construct a javascript object that combines these and call stringify on that.