C# MVC Post Model and additional data to controller from js - javascript

I am working with a custom workflow solution that I am creating. I would like to create a postback that has the model, and two integer values that represent the action and step that I have completed. I don't want to add them to the model because they are only used in this one place. The signature for this postback would be something like this.
[HttpPost]
public void ProcessWorkflowAction(EditScreenModelValidation model, int stepActionId, int stepNumber)
{
//Some work on model and actions
}
I would really like to do this through JS because that is currently how I am getting StepActionId and StepId. Is there a way to package up the model to send through JS?
var modelObj = CreateModelData();
var postObj = JSON.stringify(modelObj);
$.ajax({
type: "POST",
traditional: true,
dataType: "json",
url: "url",
data: { model: modelObj, stepActionId: stepId, stepNumber: 3 }
cache: false,
complete: function (data) {
}});
CreateModelData = function () {
var modelObj = {};
var modelArray = $('#frm').serializeArray()
$.each(modelArray, function (index, value) {
assign(modelObj, value.name, value.value);
})
return modelObj;
};
function assign(obj, prop, value) {
if (prop != undefined) {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e] =
Object.prototype.toString.call(obj[e]) === "[object Object]"
? obj[e]
: {},
prop,
value);
} else
obj[prop[0]] = value;
}
}
The model comes back as null in the controller. I have also tried the following code with the same result.
$.ajax({
type: "POST",
traditional: true,
dataType: "json",
url: "url",
data: { model: $('#frm').serializeArray(), stepActionId: stepId, stepNumber: 3 }
cache: false,
complete: function (data) {
}});

You need to build up the object, assign the properties (make sure it matches any model validation and the field names are the same as your model) and use JSON.stringify to make the conversion:
var modelObj = {};
modelObj.prop1 = $('#txtField1').val();
modelObj.prop2 = $('#txtField2').val();
// etc... make sure the properties of this model match EditScreenModelValidation
var postObj = JSON.stringify(modelObj); // convert object to json
$.ajax({
type: "POST",
traditional: true,
dataType: "json",
url: "/Workflow/Home/ProcessWorkflowAction",
data: { model: postObj, stepActionId: stepId, stepNumber: 3 }
cache: false,
complete: function (data) {
if (data.responseText.length > 0) {
var values = $.parseJSON(data.responseText)
$('#ActionErrors').html(values.message)
}
else {
location.reload();
}
}});

It's possible and pretty easy to do. MVC is nice about packaging up what you send it.
So if your model looks like:
public class TestModel
{
public string Name { get; set; }
public int Age { get; set; }
}
And your post method looks like:
[HttpPost]
public void TestMethod(TestModel model, int num1, int num2)
{
// Stuff
}
Your javascript POST would look like:
function doPost(){
$.post("/Home/TestMethod",
{
model: {
Name: "Joe",
Age: 29
},
num1 : 5,
num2 : 10
},
function (data, status) {
//Handle status if you decide to return something
});
}
Hope that helps!

So here is how I got it to work. The CreateModelData uses the (frm).serializeArray() method, but I found that if the item was disabled or not on the page, then it didn't create that property.
var modelObj = CreateModelData();
var postObj = JSON.stringify(modelObj);
$.ajax({
type: "POST",
traditional: true,
dataType: "json",
url: "url",
data: { modelString: postObj, stepActionId: stepId, stepNumber: 3 },
cache: false,
complete: function (data) {
}});
});
CreateModelData = function () {
var modelObj = {};
var modelArray = $('#frm').serializeArray();
$.each(modelArray, function (index, value) {
assign(modelObj, value.name, value.value);
})
return modelObj;
};
function assign(obj, prop, value) {
if (prop != undefined) {
if (typeof prop === "string")
prop = prop.split(".");
if (prop.length > 1) {
var e = prop.shift();
assign(obj[e] =
Object.prototype.toString.call(obj[e]) === "[object Object]"
? obj[e]
: {},
prop,
value);
} else
obj[prop[0]] = value;
}
}
On the controller side, I changed the signature to be all string values like so.
[HttpPost]
public void ProcessWorkflow(string modelString, int stepActionId, int stepNumber)
{
}
To make the modelString value the actual model object, I did this.
using (Stream s = GenerateStreamFromString(json))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(modelObj));
return (modelObj)serializer.ReadObject(s);
}
In the end, this worked for me. All the fields were there and I got no errors. When i tried to have the first variable in the controller method to be the model object, it always came back as null for me no matter what I did.

The fastest and easiest way to get all the fields in the Model is to serialize the Form which is bound with Model.
Update
The problem that you were receiving null in properties is because serializeArray() create key value format json. you just need to get re-build the json from key value to Property value that can be mapped to the model.
var modelObj = $('#formId').serializeArray()
.reduce(function (a, x) { a[x.name] = x.value; return a; }, {});
A little tweak in you ajax call instead of datatype use contentType. This is another reason you were getting null in controller's model object parameter.
$.ajax({
type: "post",
url: "/Account/RegisterSome",
data: { model: modelobj, id: 3 },
contentType: 'application/json',
cache: false,
complete: function (data) {
}
});

I resolved the issue by removing the JSON.stringify() and just posting my javascript object.

Related

How to pass local storage item to MVC controller

I am trying to pass an array of strings from my local storage (key value) to MVC controller. Here's my code:
In cshtml View file:
<script>
function getFavouriteBooks() {
var ids = JSON.parse(localStorage.getItem("bookIds"));
// returns: ["1", "2", "3"]
$.ajax({
type: "POST",
traditional: true,
url: '#Url.Action("Favourites", "Home")',
data: { ids: ids },
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
alert(result.Result);
}
}});
}
</script>
<button onClick="getFavouriteBooks()">Display Favourites</button>
My controller:
public async Task < ViewResult > Favourites(string ids) {
// code that fetches book data from API
if (data != null)
{
var bookList = JsonConvert.DeserializeObject < Book[] > (data);
foreach(var book in bookList) {
var matches = new List < bookList > ();
if (bookList.All(book => ids.Contains(book.Id))) {
matches.Add(book);
}
return View("Index", matches.ToArray());
}
}
return View("Index");
}
The controller action gets called successfully on the button click but the ids parameter is always null even though it isn't when in the console. Where am I going wrong?
from what you have described, I strongly feel this is the problem of expecting asynchronous function to behave synchronously,
await foreach(var book in bookList) {
var matches = new List < bookList > ();
if (bookList.All(book => ids.Contains(book.Id))) {
matches.Add(book);
}
return View("Index", matches.ToArray());
}
Try adding await before you call foreach loop. or better use for in loop
Thanks for your help everyone, the solution was actually to change this part of the ajax call to:
data: { ids: localStorage.getItem('videoIds') },
This code was tested in Visual Studio.
You have to create a viewModel:
public class IdsViewModel
{
public string[] Ids { get; set; }
}
Replace this:
var ids = JSON.parse(localStorage.getItem("bookIds"));
// returns: ["1", "2", "3"]
// or you can use
var ids = localStorage.getItem('videoIds'); //it still will be working
$.ajax({
type: "POST",
traditional: true,
url: '#Url.Action("Favourites", "Home")',
data: { ids: ids },
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
with this
var ids= JSON.parse(localStorage.getItem("bookIds"));
$.ajax({
type: "POST",
url: '/Home/Favourites',
data: { ids:ids },
success: function (result) {
....
and the action
public async Task <ActionResult> Favourites(IdsViewModel viewModel) {
var ids=viewModel.Ids;
.....

Pass array from client side to service side c#

I am calling a javascript function on button click using onclientclick with below function.
function addValues() {
debugger;
var arrValue = [];
var hdnValue = document.getElementById("hdn").value;
var strValue = hdnValue.split(',');
for (var i = 0; i < strValue.length; i++) {
var ddlValue = document.getElementById(strValue[i]).value;
arrValue.push(ddlValue);
}
}
arrValue array will have all the required values and how can I move this array values to server side for further process.
Update 1:
HTML:
function addValues() {
debugger;
var arrddlValue = [];
var hdnddlValue = document.getElementById("hdnDDL").value;
var strddlValue = hdnddlValue.split(',');
for (var i = 0; i < strddlValue.length; i++) {
var ddlValue = document.getElementById(strddlValue[i]).value;
arrddlValue.push(ddlValue);
}
}
$.ajax({
url: '',
data: { ddlArray: arrddlValue },
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false,
success: function (data) {
},
error: function (x, e) {
}
});
Code:
protected void btnSort_Click(object sender, EventArgs e)
{
try
{
if (Request["ddlArray[]"] != null)
{
string[] arrValues = Array.ConvertAll(Request["ddlArray[]"].ToString().Split(','), s => (s));
}
}
}
If your framework is ASP.Net you can pass it by $.ajax, I am passing array like:
$.ajax({
url: '',
data: { AbArray: arrValue },
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data) {
},
error: function (x, e) {
}
});
and get it in Back-end like:
if (request["AbArray[]"] != null)
{
int[] arrValues = Array.ConvertAll(request["AbArray[]"].ToString().Split(','), s => int.Parse(s));
}
suppose array is int.
the above sample is using Generic-Handler.
if you want to use webmethod do something like:
[WebMethod(EnableSession = true)]
public static void PassArray(List<int> arr)
{
}
and Ajax would be like:
function addValues() {
debugger;
var arrddlValue = [];
var hdnddlValue = document.getElementById("hdnDDL").value;
var strddlValue = hdnddlValue.split(',');
for (var i = 0; i < strddlValue.length; i++) {
var ddlValue = document.getElementById(strddlValue[i]).value;
arrddlValue.push(ddlValue);
}
var jsonVal = JSON.stringify({ arr: arrValue });
$.ajax({
url: 'YourPage.aspx/PassArray',
data: jsonVal,
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data) {
},
error: function (x, e) {
}
});
}
Change Ajax Url as your PassArray address which mean YourPage.aspx should be change to page name which have PassArray in it's code-behind.
For more info Read This.
If you are using Asp.net WebForm Application,
Approach 1 : you can store your array value in a hidden input control and retrieve the saved data in your c# coding.
Approach 2 : define web method in your server side c# code and pass this javascript array value as ajax call.
link for Approach 1 : https://www.aspsnippets.com/Articles/Pass-JavaScript-variable-value-to-Server-Side-Code-Behind-in-ASPNet-using-C-and-VBNet.aspx
link for Approach 2 : https://www.aspsnippets.com/Articles/Send-and-receive-JavaScript-Array-to-Web-Service-Web-Method-using-ASP.Net-AJAX.aspx
I would "stringify" the array by imploding it with a special char unlikely to appear in my values (for example: §), and then with the help of jQuery.ajax() function, I will send it to the backend (ASP.NET MVC) action method:
$.ajax({
url : 'http://a-domain.com/MyController/MyAction',
type : 'POST'
data : 'data=' + myStringifiedArray;
});
My backend would be something like this (in MyController class):
[HttpPost]
public ActionResult MyAction(string data)
{
string[] arrValue = data.Split('§');
...
}
UPDATE
For ASP.NET forms, the ajax request would be:
$.ajax({
url : 'http://a-domain.com/MyPage.aspx/MyMethod',
type : 'POST'
data : 'data=' + myStringifiedArray;
});
And the backend would be something like this:
[System.Web.Services.WebMethod]
public static void MyMethod(string data)
{
string[] arrValue = data.Split('§');
...
}
You will find a more precise explanation here: https://www.aspsnippets.com/Articles/Call-ASPNet-Page-Method-using-jQuery-AJAX-Example.aspx

JSON Object always return undefined with AJAX

The JSON Object always return undefined in spite of the object contains data, i check it by using breakpoints in debugging
This is Action method in Controller:
public JsonResult GetMoreComments(int CommsCount, int ArticleID)
{
List<ComViewModel> comms = articleService.GetMoreComments(ArticleID, CommsCount);
return Json( comms );
}
and I also replaced the code in Action method to simple code like that but not work too:
public JsonResult GetMoreComments(int CommsCount, int ArticleID)
{
ComViewModel com = new ComViewModel
{
CommentContent = "cooooooooooontent",
CommentID = 99,
SpamCount = 22
};
return Json( com );
}
This is jQuery code for AJAX:
function GetMoreComments() {
$.ajax({
type: 'GET',
data: { CommsCount: #Model.Comments.Count, ArticleID: #Model.ArticleID },
url: '#Url.Action("GetMoreComments", "Comment")',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (result) {
var JsonParseData = JSON.parse(result);
alert(JsonParseData[0].CommentID)
alert(result[0].CommentID);
alert(result[0]["CommentID"]);
}
});
}
Usually you would have to parse your data if you need to alert it the way you have it. alert(result) should show data. If you need to access array of objects you must parse it first. Here is my example....
jQuery.post(ajaxurl, data, function(response) {
alert('Got this from the server: ' + response);
//PARSE data if you need to access objects
var resultstring = response.replace(',]',']');
var JsonParseData = JSON.parse(resultstring);
alert(JsonParseData[0].address)
});
That is wordpress ajax but its the same concept

pass jquery array of objects to mvc action which accepts a list object

I have a form in my view which has only one textarea input initially and user can add more textarea inputs if he wants with jquery. My problem is related to second case. After submitting the form i am getting an array of objects in console but when i am passing this array to mvc action in my controller it is coming to be null.
I have tried these solution but did not succeed:
Send array of Objects to MVC Controller
POST a list of objects to MVC 5 Controller
here is my code:-
jquery code:
$('body').on('submit', '#addTextForm', function () {
console.log($(this));
var frmData = $(this).serializeArray();
console.log(frmData);
$.ajax({
type: 'post',
url: '/Dashboard/UploadText',
contentType: 'application/json',
data: JSON.stringify({ obj: frmData }),
success: function (data) {
console.log(data);
},
error: function (data) {
console.log(data);
}
});
return false;
});
MVC action:
[HttpPost]
public string UploadText(SliderTextList obj)
{
return "success";
}
my object class:
public class SliderText
{
[JsonProperty("Id")]
public int Id { get; set; }
[JsonProperty("SlideName")]
public string SlideName { get; set; }
[JsonProperty("Content")]
public string Content { get; set; }
}
public class SliderTextList
{
public List<SliderText> AllTexts { get; set; }
}
I have to store the Content in json file with Id and SlideName, so i think i have to pass a list object in mvc action Uploadtext which is coming out to be null always. Please help.
$(document).ready(function(){
$('body').on('submit', '#addTextForm', function () {
var listData=[];
var oInputs = new Array();
oInputs = document.getElementsByTag('input' );
var k=1;
for ( i = 0; i < oInputs.length; i++ )
{
if ( oInputs[i].type == 'textarea' )
{
var obj=new Object();
obj.Id=k;
obj.SlideName=oInputs[i].Name;
obj.Content=oInputs[i].Value;
K=parseInt(k)+1;
listData.push(obj);
}
}
$.ajax({
type: 'post',
url: '/Dashboard/UploadText',
contentType: 'application/json',
data: JSON.stringify(listData),
success: function (data) {
console.log(data);
},
error: function (data) {
console.log(data);
}
});
return false;
});
});
Since the sever side expects a string as argument obj as a query string I think this is what you need.
data: {
obj: JSON.stringify(frmData)
},
as an alternative using as Stephen suggested on the comments
data: {
obj: $('#addTextForm').serialize()
},

Pass json/javascript data/objects to c# function using ajax

I'm using FullCalendar (http://arshaw.com/fullcalendar/) and I need help with passing data using json to a c# function in the code behind page of my ASP.net page.
I am using json to load data like so in my FullCalendar web application:
Code behind:
[WebMethod]
public static List<Event> GetEvents()
{
List<Event> events = new List<Event>();
events.Add(new Event()
{
EventID = 1,
EventName = "EventName 1",
StartDate = DateTime.Now.ToString("MM-dd-yyyy"),
EndDate = DateTime.Now.AddDays(2).ToString("MM-dd-yyyy"),
EventColor = "red"
});
events.Add(new Event()
{
EventID = 2,
EventName = "EventName 2",
StartDate = DateTime.Now.AddDays(4).ToString("MM-dd-yyyy"),
EndDate = DateTime.Now.AddDays(5).ToString("MM-dd-yyyy"),
EventColor = "green"
});
return events;
}
asp.x page:
events: function(start, end, callback)
{
$.ajax(
{
type: 'POST',
contentType: 'application/json',
data: "{}",
dataType: 'json',
url: "Calendar.aspx/GetEvents",
cache: false,
success: function (response) {
var events = $.map(response.d, function (item, i) {
var event = new Object();
event.id = item.EventID;
event.start = new Date(item.StartDate);
event.end = new Date(item.EndDate);
event.title = item.EventName;
event.color = item.EventColor;
return event;
})
callback(events);
},
error: function (err) {
alert('Error');
}
});
},
This is working fine. Now I want to save data by calling a function and passing it data. Here is what I have done so far:
Code behind:
[WebMethod]
public static bool SaveEvents(List<Event> events)
{
//iterate through the events and save to database
return true;
}
asp.x page
function save() {
var eventsFromCalendar = $('#calendar').fullCalendar('clientEvents');
var events = $.map(eventsFromCalendar, function (item, i) {
var event = new Object();
event.id = item.id;
event.start = item.start;
event.end = item.end;
event.title = item.title;
event.color = item.color;
return event;
});
$.ajax(
{
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(events), **<-- I have to pass data here but how???**
dataType: 'json',
url: "Calendar.aspx/SaveEvents",
cache: false,
success: function (response) {
alert('Events saved successfully');
},
error: function (err) {
alert('Error Saving Events');
}
});
return false;
}
The above ajax post is where I need help with. The variable events contais all the FullCalendar event info.
How do I pass the data 'events' to the function 'SaveEvents'?
I can change the SaveEvents signature if need be.
EDIT
If I change my c# function to use an array like s0:
[WebMethod]
public static bool SaveEvents(Event[] newEvents)
{
return true;
}
And pass the following data through:
data: JSON.stringify({ newEvents: events }),
Then the function 'SaveEvents' gets called with an array of size 4 but all the data values are null, why is this?
Thanks
Obvious from your code that you have a c# class as
public class Events
{
public int EventID {get; set;}
public string EventName {get;set;}
public StartDate {get; set;}
public string end {get; set;}
public string color {get; set;}
}
So take json array. A sample here
// Array which would be provided to c# method as data
var newEvents=[
{
EventID : 1,
EventName : "EventName 1",
StartDate : "2015-01-01",
EndDate : "2015-01-03",
EventColor : "red"
},
{
EventID : 2,
EventName : "EventName 2",
StartDate : "2015-01-02",
EndDate : "2015-01-04",
EventColor : "green"
}
];
Now the ajax request which passes JSON objects to posted URL
$.ajax
({
type: 'POST',
contentType: 'json',
data: {newEvents:newEvents},// Pass data as it is. Do not stringyfy
dataType: 'json',
url: "Calendar.aspx/SaveEvents"
success: function (response) {
alert('Events saved successfully');
},
error: function (err) {
alert('Error Saving Events');
}
});
Update :
To make sure that there is nothing else wrong please test your Save Events as. If it goes fine above should work as well, As it is working for me :)
[WebMethod]
public static bool SaveEvents(string EventName)
{
//iterate through the events and save to database
return true;
}
$.ajax
({
type: 'POST',
contentType: 'json',
data: {EventName:'myevet 1'},
url: "Calendar.aspx/SaveEvents",
cache: false,
success: function (response) {
alert('Events saved successfully');
},
error: function (err) {
alert('Error Saving Events');
}
});

Categories