I need to populate the ajax data attribute with one or many key value pairs to post up to a MVC controller action. The snag is that I want to use one js function to send data to different controller actions each with different signatures. Here goes:
MVC View
#{
var Params = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("param1","foo"),
new KeyValuePair<string, string>("param2","bar"),
};
var targetUrl = "/MyActionName/";
var myParams = #Json.Encode(Params);
var clickFunction = $"myFunction('{targetUrl}', {myParams})";
}
Do It
Javascript function
function myFunction(url, paramData) {
var dataParams = [];
paramData.forEach(function (arrayItem) {
var key = arrayItem.Key;
var value = arrayItem.Value;
dataParams[key] = value;
});
// This works
$.ajax({
url: url,
data: {
param1: "foo",
param2: "bar"
},
success: function (partialViewResult) {
$('#TargetDIV').html(partialViewResult);
},
});
// This doesn't
$.ajax({
url: url,
data: { dataParams },
success: function (partialViewResult) {
$('#TargetDIV').html(partialViewResult);
},
});
}
Controller Action Example 1
public PartialViewResult MyAction1(string param1, string param2)
{
....
}
Controller Action Example 2
public PartialViewResult MyAction2(string apple, string orange, string grape)
{
....
}
Controller Action Example 3
public PartialViewResult MyAction3(string pig, string cow, string dog, string cat)
{
....
}
I'd like myFunction to be used to post up to multiple controller actions with varying signatures. So i'd just need to throw a list of KeyValuePair at myFunction and will handle it.
Tried so far without any luck:
using JSON.stringify but is doesn't format dataParams in the correct way.
using a MVC model instead of many separate params. This is because the param names will be different so one model won't fit all scenarios
If I can get this to work i'd then extend it to handle data types other than string but for sake of simplicity i've stuck to string here
Any help would be very much appreciated
It is wrong dataParams you must to set is as an object
function myFunction(url, paramData) {
var dataParams = {};
paramData.forEach(function (arrayItem) {
var key = arrayItem.Key;
var value = arrayItem.Value;
dataParams[key] = value;
});
// This works
$.ajax({
url: url,
data: {
param1: "foo",
param2: "bar"
},
success: function (partialViewResult) {
$('#TargetDIV').html(partialViewResult);
},
});
// This doesn't
$.ajax({
url: url,
data: dataParams,
success: function (partialViewResult) {
$('#TargetDIV').html(partialViewResult);
},
});
}
Related
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
is there a way to pass an array of object and then assign it to model?
i searched that making the same variable name in your model and object will do the work but it doesn't work for me.
the model always get null values.
var answers = [];
var answerOthers = [];
var comment = $("#message").val();
$("input:radio:checked").each(function () {
var questno = $(this).attr("data-question");
var ansid = $(this).val();
answers.push({ QUESTIONID: questno, ANSWERID: ansid});
if ($(this).val() == 3)
{
var txtOther = $("#otherTxt-" + $(this).attr("data-question")).val();
answerOthers.push({
QUESTIONID: questno,
ANSWER: txtOther
});
}
});
$.ajax({
url: 'insertQuestions',
data: { answers: answers, answer_others: answerOthers, userid: userid , comment: comment },
method: 'GET',
success: function ()
{
alert("saved");
},
error: function (e)
{
console.log(e);
}
});
c# controller
public void insertQuestions(List<ratingsModel.ANSWERS> answers,
List<ratingsModel.ANSWERS_OTHERS> answer_others, int userid , string comment)
{
insertAnswers(answers,userid);
insertAnswer_others(answer_others, userid);
MySqlConnection myconn2 = new MySqlConnection(cmn.connstring);
myconn2.Open();
string query3 = "INSERT INTO comments (userid,comment) VALUES" +
" (#userid,#comment)";
MySqlCommand cmd2 = new MySqlCommand(query3, myconn2);
cmd2.Parameters.AddWithValue("#userid", userid);
cmd2.Parameters.AddWithValue("#comment", comment);
cmd2.ExecuteNonQuery();
myconn2.Close();
}
You cannot do that with a GET (the data you pass to the method would need to be a query string and to represent your collections you need individual name/value pairs with collection indexers, for example
data { [0].QUESTIONID: xx, [0].ANSWERID: yy [1].QUESTIONID: zz, .... etc }
But it should not be a GET in any case. Your method is changing data so it should be a POST (and in addition, if your collections were large, your would exceed the query string limit and throw an exception)
Change the ajax code to
$.ajax({
url: #Url.Action('insertQuestions'), // dont hard code your url's
data: JSON.stringify({ answers: answers, answer_others: answerOthers, userid: userid, comment: comment }) // modify,
contentType: 'application/json', // add
method: 'POST', // change
success: function() {
....
As a side note, if you had generated your form correctly using the strongly typed HtmlHelper methods, then you code could simply have been
$.ajax({
url: #Url.Action('insertQuestions'),
data: $('form').serialize(),
method: 'POST',
success: function() {
....
and none of the code for generating the arrays would be required.
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.
I am sending json list from my controller:
public ActionResult LoadTree()
{
List<ListItem> list = new List<ListItem>() {
new ListItem() { Text = "Keyvan Nayyeri" },
new ListItem() { Text = "Simone Chiaretta" },
new ListItem() { Text = "Scott Guthrie" },
new ListItem() { Text = "Scott Hanselman" },
new ListItem() { Text = "Phil Haack" },
new ListItem() { Text = "Rob Conery" }
};
return new JsonResult { Data = list };
}
Trying to get the list in my view using:
var text =
$.ajax({
url: '/CourseCases/LoadTree',
dataType: 'json',
data: { },
cache: false,
type: 'GET',
success: function (data) {
}
});
alert(text);
I just get [object object]. How I can get the actual value of the object? Thanks in advance.
First you have to set the JsonRequestBehavior = JsonRequestBehavior.AllowGet in the JsonResult.
public ActionResult LoadTree()
{
List<ListItem> list = new List<ListItem>() {
new ListItem() { Text = "Keyvan Nayyeri" },
new ListItem() { Text = "Simone Chiaretta" },
new ListItem() { Text = "Scott Guthrie" },
new ListItem() { Text = "Scott Hanselman" },
new ListItem() { Text = "Phil Haack" },
new ListItem() { Text = "Rob Conery" }
};
return new JsonResult { Data = list, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
<script type="text/javascript">
$.ajax({
url: '/Home/LoadTree',
dataType: 'json',
data: {},
cache: false,
type: 'GET',
success: function (data) {
alert(data.length); // 6
// do whatever with the data
}
});
</script>
in success function you have to parse json to get actual data e.g.
var jsObject = JSON.parse(data);
and then access each item like jsObject.List[0].Text etc
Simple problem here. In your controller, you're actually assigning the list to a variable named Data inside the response data collection. Just because your success function takes a data parameter doesn't mean that the Data value you set in your controller automagically will become the data variable.
As your Data list is inside the data object: you need to do:
data.Data
inside your success function. Try this:
success: function(data) {
alert(data.Data.length);
}
function $.ajax() does not return value from server, so var text = $.ajax() will not work. You need to look at success handler instead
success: function (data) {
// data is the result of your ajax request
}
I strongly recommend you to read more at jQuery.Ajax
success(data, textStatus, jqXHR) A function to be
called if the request succeeds. The function gets passed three
arguments: The data returned from the server, formatted according to
the dataType parameter; a string describing the status; and the jqXHR
(in jQuery 1.4.x, XMLHttpRequest) object. As of jQuery 1.5, the
success setting can accept an array of functions. Each function will
be called in turn. This is an Ajax Event.
I am trying to bind data from json. In the controller, I am sending
......
public JsonResult LoadTree()
........
return Json(jn, JsonRequestBehavior.AllowGet);
In debug I get the values in jn (47 items, each has two enteries (text and value).
In the view, I am using the following script:
function onDataBinding(e) {
var url = 'CourseCases/LoadTree';
var result;
$.ajax({
url: url,
data: {},
contentType: "application/json",
success: function (data) {
alert(data);
var treeview = $("#TreeView").data("tTreeView");
treeview.bindTo(data);
}
});
}
It does not work, alert shows object, object; and the treeview is blank!
Any idea why? Thanks in advance.
Actually the properties that you are sending should be called Value and Text instead of value and text. Here's an example that works fine for me.
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult LoadTree()
{
var jn = new[]
{
new { Value = "1", Text = "Item 1" },
new { Value = "2", Text = "Item 2" },
new { Value = "3", Text = "Item 3" },
};
return Json(jn, JsonRequestBehavior.AllowGet);
}
}
View (~/Views/Home/Index.cshtml):
<script type="text/javascript">
function onDataBinding(e) {
var url = '#Url.Action("LoadTree")';
var result;
$.ajax({
url: url,
data: { },
success: function (data) {
var treeview = $("#TreeView").data("tTreeView");
treeview.bindTo(data);
}
});
}
</script>
#(Html
.Telerik()
.TreeView()
.Name("TreeView")
.ClientEvents(events =>
{
events.OnDataBinding("onDataBinding");
})
)
Probably you should call treeview.bindTo in the callback method of $.post directly. I guess with the current code you might bind the treeview to jsonObject == jn before jn == content is ensured in the callback. If you alert you add a big delay and it gives the AJAX post enough time to complete and run the callback.