ASP.NET MVC controller accept javascript object - javascript

From chrome developer tools I see that my request is sending this info to my controller:
models:[{"Id":null,"Start":"2014-06-11T12:17:52.452Z","End":"2014-06-11T12:17:52.452Z","Name":"test","Status":"test"}]
How can I accept it in my MVC controller?
It looks like to be a javascript array with one element.
On serverside I have method accepting : Foo(Bar models) and also tried Foo(List<Bar> models)
The models value is always null. Any suggestions, how to get the value to my server?

So to pass the information using AJAX, you need to supply two parameters: dataType and contentType. (I suppose dataType is optional, but if you're expecting JSON back it's better to supply it.). The contentType, however, lets MVC [the ModelBinder] know the incoming request isn't just a string, but that it's an object that needs to be deserialized back into objects.
with that said, something like the following should work for your circumstance:
// This is your to-be-sent data'
// However you collect it, but for now we're storing it as a plain object.
var jso = { models: [{ "Id": null, "Start": "2014-06-11T12:17:52.452Z", "End": "2014-06-11T12:17:52.452Z", "Name": "test", "Status": "test" }] }
// Here we turn it into JSON
var json = JSON.stringify(jso);
// And now we send it off to the controller/action:
$.ajax({
url: '#Url.Action("SomeAction","SomeController")',
type: 'POST',
data: json, // pass of data serialized
dataType: 'json', // expecting json back
contentType: 'application/json; charset=utf-8', // hey ModelBinder, deserialize this!
})/* handle the Deferred callbacks (.done, .fail, .always) */;
Then, in your controller:
public class SomeController : Controller
{
[HttpPost]
public JsonResult SomeAction(IList<MyModel> models)
{
// Should pass now
if (ModelState.IsValid)
{
// Handle it and return back the response
// Given the above, you have something like the following now
// assigned to "models":
// models = new List<MyModel> {
// new MyModel {
// Id = null,
// Start = new DateTime(2014, 11, 6, 12, 17, 52),
// End = new DateTime(2014, 11, 6, 12, 17, 52),
// Name = "test",
// Status = "test"
// }
// };
return Json(new {Models = models }); // just to see it come back
}
return Json(new { Error = true, Message = "Invalid model" });
}
}
Working example can be seen On GitHub by the way.

Here is a pretty simple example using POST and Json.Net to deserialize into a JObject
Get Json.Net via Nuget.
API Controller:
[HttpPost]
public dynamic UpdateItem([FromBody]dynamic item)
{
var qp = JObject.Parse(item.ToString());
string oid = qp.SelectToken("oid").ToString();
...
Make sure your route and param name matches an actual route, for example
config.Routes.MapHttpRoute(
name: "ItemApi",
routeTemplate: "api/{controller}/{action}/{item}",
defaults: new { item = RouteParameter.Optional }
);
Usually found under App_Start/WebApiConfig.cs or in global.asax.
And then post to it using jquery ajax:
var param = new Object();
param.oid = "somestring";
param.name = "john";
param.number = 3;
$.ajax({
type: "POST",
url: "/api/YourController/UpdateItem",
data: JSON.stringify(param),
contentType: 'application/json',
success: function (data) {
// do stuff
},
error: function (e) {
console.error("error", e);
}
});
EDIT: I see now that you are using a mvc controller. I assumed a webapi controller for my answer. Apologizes :)

It is mvc's default behaviour it will convert json object to your C# object automatically. just makesure property name matches. Check this may help

For that you need to use JsonConvert.DeserializeObject() method.
Like this
List<YourModelClass> myObjList =
(List<YourModelClass>)Newtonsoft.Json.JsonConvert.DeserializeObject(models, typeof(List<test>));
Then return this object named - myObjList to your view or whatever...
And For single object -
return JsonConvert.DeserializeObject<YourModelClass>(models);

Related

Manipulate ajax response

I have a ajax post method. I get an object from the backend
$.ajax({
type: "POST",
url: URL_one,
data: submitData
}).then(function (response) {
console.log("Ajax response", response);
});
and when i do a console.log(response); inside the post method, i see the following data.
>Object{Info:Array[200]}
>Info:Array[200]
>[0-99]
>0:Object
name:'Ashley'
on_pay: true
valid:"0"
>[100-199]
So each array has objects like one mentioned above with name, on_pay and valid. I want to do the following
Since all on_pay values are true in my case, i need to convert it to false. Also valid has string of 0. I need to put all values as blank instead of 0.
Is it possible to do ?? Can someone please shed some light on these.
Considering the JSON structure that you show, following should work to change the on_pay value:
response.Info.forEach(function(item){
item.on_pay = false;
});
If I'm understanding your question correctly, response is an array of items. You want to keep those items intact, but turn the on_pay property false and valid to an empty string.
You can use Array::map() to transform each item.
/*jslint node:true*/
"use strict";
// I am assuming your response looks something like this
var response = {
Info: [
{
name: "Ashley",
on_pay: true,
valid: "0"
},
{
name: "Jim",
on_pay: true,
valid: "0"
},
{
name: "John",
on_pay: true,
valid: "0"
}
]
};
// This will produce a new variable that will hold the transformed Info array
var fixedResponseInfo = response.Info.map(function (item) {
item.on_pay = false;
item.valid = "";
return item;
});
// This will edit the response.Info array in place
response.Info.forEach(function (item) {
item.on_pay = false;
item.valid = "";
});
console.log(fixedResponseInfo);
console.log(response);
This will keep your original response variable and produce a new variable fixedResponseInfo that contains the transformed array. If you don't care whether data in response is changed, you can use Array::forEach() to iterate instead.

Backbone parse server response to model

I'm trying to deal with a server response, and am a little confused how to turn the json response into Backbone Models.
My Backbone model looks like so:
Entities.Recipe = Backbone.Model.extend({
defaults: {
id: '',
name: '',
introduction: ''
},
parse: function (response)
{
if(._isObject(response.results)){
return response.results
else {
return response
}
})
Entities.RecipeCollection = Backbone.Collection.extend({
url: 'recipes',
model: Entities.Recipe
)}
var API = {
getRecipeEntities: function (){
var recipes = new Entities.RecipeCollection()
var defer = $.Deferred()
recipes.fetch({
url: 'http://3rdpartyApilocation.com/recipes'
success: function (data) {
defer.resolve(data)
}
})
var promise = defer.promise()
$.when(promise).done(function (fetchedData)
{})
return promise
}
RecipeManager.reqres.setHandler('recipe:entities', function()
{
return API.getRecipeEntities()
}
And the response.results is an Array of objects - with each object having an id key, a name key and an introduction key. But because I am so inexperienced with Backbone I have no idea how to map those results to the model?
I have installed Chromes Marionette inspector and when I look at the entire array of results seems to be passed to the model, rather than each individual object within each response.result being set to each individual model. Sorry if I can't be more clear - I'm very new to Backbone...
Perhaps your confusion is because you're in fact able to use parse on a model or on a collection. And from your explanation it looks like the response.results object returns a list of objects that you want to become models in your application. But because you're catching that object in a model, the model doesn't know what to do with that array.
Let's say you have a response like this:
{
"status": "ok",
"results": [
{
"id": 1,
"name": "Pie"
}, {
"id": 2,
"name": "Rice"
}, {
"id": 3,
"name": "Meatballs"
}
]
}
Then you would just use parse on your Collection to let it know the response isn't array itself, and help it find it in the results property.
Here's a working example:
var Recipe = Backbone.Model.extend();
var Recipes = Backbone.Collection.extend({
model: Recipe,
url: 'http://www.mocky.io/v2/56390090120000fa08a61a57',
parse: function(response){
return response.results;
}
});
var recipes = new Recipes();
recipes.fetch().done(function(){
recipes.each(function(recipe){
/** Just demo of the fetched data */
$(document.body).append('<p>'+ recipe.get('name') +'</p>');
});
});
<script src='http://code.jquery.com/jquery.js'></script>
<script src='http://underscorejs.org/underscore.js'></script>
<script src='http://backbonejs.org/backbone.js'></script>

AngularJS Not able to pass model data to server model appears as empty string

I'm trying to send some simple data to the server. I take the originally received server data used to create dynamic forms, quickly clean up unnecessary keys using delete formData['not_needed'], and then I wanted to add the model that has been created before posting to the server, but when I check the data objects model key that I'm trying to add it is always an empty string. I can either send one or the other, but can't seem to add one object to another as a key-value pair.
// Abridged version
var formData = $scope.responseData; // original server data to build forms
delete formData['config_data']; // remove unnecessary keys
formData.model = $scope.formModel; // add model key
$http.post('/restful/api', formData).then(function(success) {...}, function(error) {...});
The output of passed data from the server looks like:
{ id: "1", type: "type_of_form", name: "name_of_package", model: "" } // model always empty
Is this an issue using $scope?
UPDATE
Even when I hardcode the outgoing keys:
var packageData = {
"packageid": $scope.formData.id, // makes it to server
"desc": $scope.formData.desc, // also makes it to server
"data": $scope.formModel // is just an empty string
}
But formModel filled from some dumby form data when logged to console and printed out to the screen using a filter { formModel | json } looks like:
formModel = {
"document_date": "1234",
"first_name0": "1",
"first_name1": "2",
"first_name2": "3",
"first_name3": "4"
}
It could be that you're running into the by-now famous "AngularJS cannot form-URL-encode data it POSTs by default" pitfall; if so, you'll need to do this before you try and post:
.config(['$httpProvider', function ($httpProvider) {
// Intercept POST requests, convert to standard form encoding
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.transformRequest.unshift(function (data, headersGetter) {
var key, result = [];
for (key in data) {
if (data.hasOwnProperty(key)) {
result.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
}
}
return result.join("&");
});
}]);
via How can I post data as form data instead of a request payload?

Angular Ajax request sending object

i am editing content in an object saved in my AngularJs scope. Once submited i execute the following function:
$scope.saveQuestion = function(){
var request = $http({
method: "post",
url: "/manager/evaluations/evaluations/manage_questions/537c6179-8ed8-49b4-ac6b-25715f550349",
data: {EvaluationQuestion: $scope.newquestion}
});
}
$scope.newquestion has the following object:
[relevance: 3, evaluation_topic_id: 1, type: "text", action: "add", name: "asdfasdfsadfas"]
But the ajax request on the is just showing a Request Payload with:
Request Payloadview source
{EvaluationQuestion:[]}
EvaluationQuestion: []
Can any one guess why the sent data is empty?
It seems your $scope.newquestion is an Array, not an Object.
JSON doesn't support an Array data type with named keys in it. For example:
var foo = [];
foo['bar'] = 'One';
foo.baz = 'Two';
JSON.stringify(foo); // return "[]"
If the $scope.newquestion isn't required to be an Array, just use an Object.
Instead of
$scope.newquestion = [];
change it to:
$scope.newquestion = {};
I think you are using a wrong JSON syntax in $scope.newquestion.
Here you are defining an object which is supposed to be enclosed in {} but you are enclosing it in [] which stands for an array. I js arrays you cannot have [name1: value1, name2: value2].
Try replacing the square brackets with curely brackets, something like this:
{relevance: 3, evaluation_topic_id: 1, type: "text", action: "add", name: "asdfasdfsadfas"}
Hope that helps.
Try this:
data: {EvaluationQuestion: angular.toJson($scope.newquestion)}

Backbone.js model with collection

I have 2 models and one collection. JobSummary is a model, JobSummaryList is a collection of JobSummary items, and then I have a JobSummarySnapshot model that contains a JobSummaryList:
JobSummary = Backbone.Model.extend({});
JobSummaryList = Backbone.Collection.extend({
model: JobSummary
});
JobSummarySnapshot = Backbone.Model.extend({
url: '/JobSummaryList',
defaults: {
pageNumber: 1,
summaryList: new JobSummaryList()
}
});
When I call fetch on the JobSummarySnapshot object, it gets everything... Except when I move through the summaryList collection they are all of type object and not JobSummary.
I suppose this makes sense since other than the defaults object, it doesn't know that the summaryList should be of type JobSummaryList. I can go through each item and convert it to a JobSummary object, but I was hoping there was a way to do it without having to do it manually.
Here's my test code (working jsfiddle here):
var returnData = {
pageNumber: 3,
summaryList: [
{
id: 5,
name: 'name1'},
{
id: 6,
name: 'name2'}
]
};
var fakeserver = sinon.fakeServer.create();
fakeserver.respondWith('GET', '/JobSummaryList', [200,
{
'Content-Type': 'application/json'},
JSON.stringify(returnData)]);
var callback = sinon.spy();
var summarySnapshot = new JobSummarySnapshot();
summarySnapshot.bind('change', callback);
summarySnapshot.fetch();
fakeserver.respond();
var theReturnedList = callback.getCall(0).args[0].attributes.summaryList;
_.each(theReturnedList, function(item) {
console.log('Original Item: ');
console.log(item instanceof JobSummary); // IS FALSE
var convertedItem = new JobSummary(item);
console.log('converted item: ');
console.log(convertedItem instanceof JobSummary); // IS TRUE
});
UPDATE:
It occurred to me that I could override the parse function and set it that way... I have this now:
JobSummarySnapshot = Backbone.Model.extend({
url: '/JobSummaryList',
defaults: {
pageNumber: 1,
summaryList: new JobSummaryList()
},
parse: function(response) {
this.set({pageNumber: response.pageNumber});
var summaryList = new JobSummaryList();
summaryList.add(response.summaryList);
this.set({summaryList: summaryList});
}
});
This works so far. Leaving the question open in case someone has comment on it....
Your parse() function shouldn't set() anything, its a better practice to just return the attributes, Backbone will take care of setting it. e.g.
parse: function(response) {
response.summaryList = new JobSummaryList(response.summaryList);
return response;
}
Whatever you return from parse() is passed to set().
Not returning anything (which is like returning undefined) is the same as calling set(undefined), which could cause it not to pass validation, or some other unexpected results if your custom validate()/set() methods expects to get an object. If your validation or set() method fails because of that, the options.success callback passed to Backbone.Model#fetch() won't be called.
Also, to make this more generic, so that set()ing to a plain object from other places (and not only from the server response) also effects it, you might want to override set() instead:
set: function(attributes, options) {
if (attributes.summaryList !== undefined && !(attributes.summaryList instanceof JobSummaryList)) {
attributes.summaryList = new JobSummaryList(attributes.summaryList);
}
return Backbone.Model.prototype.set.call(this, attributes, options);
}
You might also find Backbone-relational interesting - it makes it much easier to deal with collections/models nested inside models.
edit I forgot to return from the set() method, the code is now updated

Categories

Resources