Angular Ajax request sending object - javascript

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)}

Related

JavaScript: How to properly loop through array and use values as keys?

I am getting a JSON-string from a remote endpoint and want to use values as keys. So I am looping through the result like that:
(function() {
// Create the connector object
var myConnector = tableau.makeConnector();
var definitions = [];
// Define the schema
myConnector.getSchema = function(schemaCallback) {
$.ajax({
url: apiUrl,
type: 'GET',
crossDomain: true,
cache: false,
headers: {
'X-Auth-Token':'123',
'X-Auth-User':'user1'
},
dataType: "json",
success: function(response){
$.each(response,function(key,value){
console.log("inside loop");
console.log(value);
definitions[value.id]
= value.name;
});
console.log("inside ajax");
console.log(definitions);
}
});
console.log("done");
console.log(definitions);
// this is where I want to loop through my result
// whithout success (no console output
for (var key in definitions) {
console.log(key);
}
}; // myConnector.getSchema = function(schemaCallback) {
})(); //function() {
This is the response from the API:
[
{
"id": 123,
"name": "Name1"
},
{
"id": 456,
"name": "Name2"
},
{
"id": 789,
"name": "Name3"
}]
This is the output of the first log command, inside the loop:
{id: 123, name: "Name1"}
id: 123
name: "Name1"
__proto__: Object
The problem is, the last log looks like this:
[123: "Name1", 456: "Name3", 789: "Name4"]
123: "Name1"
456: "Name2"
789: "Name3"
length: 0
__proto__: Array(0)
The problem is clearly: The array length is shown as zero. And this I do not understand.
Later in this script I want to loop through this array again, but because of this strange result, I am not able to address the index keys.
What is it, that I am doing wrong?
Additional information
I am working on a web connector for Tableau that will connect to an RESTful service's endpoint. Unfortunately I cannot publish the actual RESTful URL, because it provides private data.
I am using this simulator: http://tableau.github.io/webdataconnector/Simulator/
I added all the surroundings to the upper source code. There are few more lines of source code, but it's absolutely not related to my work (one more different loop and variable definitions).
I now tried the script in Firefox (Chrome before). The only result I get here is
done myConnector.js:97:5
[]
​
length: 0
​
<prototype>: Array []
All the other console.log's are not triggered.
Also Firefox complains about CORS, this is known because I already fixed the CORS-header server-side. But nevertheless at the end data is being received and populated to the simulator I am using (see URL above)!
Clearly I am misunderstanding something here...
Try this. Not work in IE. For crossbrowsers support use regular for loop.
for (var object of response) {
console.log(object.id);
console.log(object.name);
}
Regular for
var len = response.length;
for ( var i = 0; i < len; i++ ) {
var currentObject = response[i];
console.log(currentObject.id);
console.log(currentObject.name);
}
In this way you get properties and then can use they as key for looping over another array/object.
You can try initializing definitions as an object instead of array ie. var definitions = {} and the ids its properties. So that you can easily loop through it with a for..in loop.
As the AJAX call is async the log might run on the empty array definitions.
for (id in definitions) {
// Logic
}
var len = Object.keys(definitions).length
OK, this is on me and a misunderstanding of Ajax and asynchronious request. The comments on my question helped to see the problem.
As stated above, I am calling this script from another server (http://tableau.github.io/webdataconnector/Simulator/). The script itself sends a request to a third server.
Forcing the ajax-function to work synchroniously works:
$.ajax({
url: apiUrl,
type: 'GET',
crossDomain: true,
cache: false,
async: false,
...})
Now the console show the array as actually filled:
(790) [empty × 123, "Name1", empty × 123, "Name2", empty × 333, "Name3"]
123: "Name1"
456: "Name2"
789: "Name3"
length: 929
__proto__: Array(0)
So finally, it's not about referencing the array / object the wrong way, it's about the asynchronious call.

why does PHP json_encode ignore empty arrays?

I have the following javascript that sends data to a PHP function:
<script>
var mydata = {
id:123,
name: 'mike',
orders: []
};
$.ajax({
type: 'POST',
url: 'test.php',
data: {save_data:mydata},
success: function(data) {
alert('php received: ' + data);
}
});
</script>
and my test.php file contains the following code:
<?php
if (isset($_POST['save_data'])) {
$json = json_encode($_POST['save_data']);
echo $json; // just to check what has been received
exit();
}
?>
What I expect to received from PHP is:
{"id":"123","name":"mike","orders":"[]"}
What I got back is {"id":"123","name":"mike"}
Notice that orders array has been eliminated from the output. No place holder for it. I tried adding some dummy elements in the array, and that worked fine, and I received the array back with the elements.
I need PHP to receive the json object as is, even if it contains empty arrays.
How can I do that?
The JSON object is created inside PHP. Before then you just have form data.
jQuery will encode form data in a PHP-friendly style.
If you give it:
data: { foo: [1, 2, 3] }
It will convert that to:
foo[]=1&foo[]=2&foo[]=3
(although it will percent encode the [])
You get a key=value pair for each value.
If you have an empty array then you don't have any values, so you don't get any key=value pairs.
There is no way to encode "an empty array" using PHP's extensions to the form url encoding syntax.
You have two basic options:
Tell PHP about what data structure you want to create in advance and have it fill in the empty arrays.
Generate the JSON on the client
It is not error of PHP. It cause by Jquery will igrone empty array when send it to server. So you have to parse array in 'orders' key to string JSON before send
var mydata = {
id:123,
name: 'mike',
orders: []
};
Change to
var mydata = {
id:123,
name: 'mike',
orders: JSON.stringify([])
};

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.

ASP.NET MVC controller accept javascript object

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);

Knockout and coffeescript - uncouched type error

I want to maintain simple app with knockout and coffee script. I want to add array of Json objects like:
[
{
Name = "",
Subscribe = "",
ScrollOfDish = [0]
},
{
Name = "",
Subscribe = "",
ScrollOfDish = [0]
}
]
Here is my code:
class Complex
constructor: ()->
#ComplexItems = ko.observableArray()
#getAllComplex()
self = this
getAllComplex:()->
$.ajax
type: "POST"
url: "/Complex/GetAllComplex"
data: {}
dataType:"json"
contentType:"json"
success:(res)->
self.ComplexItems res // here is the problem
$(document).ready ()->
window.model = new Complex()
ko.applyBindings(model)
But I have got a problem with uncouched type error ComplexItems is not a function. Of course, I try reverse self.ComplexItems and model.ComplexItems - and it does not work - but I want to understand why my example is not working.
Your self = this is in the wrong place.. right now it's making 'self' point to the constructor function (instead of any instance of the class..).
Should be:
class Complex
constructor: ()->
#ComplexItems = ko.observableArray()
#getAllComplex()
getAllComplex:()->
self = this
$.ajax
type: "POST"
url: "/Complex/GetAllComplex"
data: {}
dataType:"json"
contentType:"json"
success:(res)->
self.ComplexItems res
$(document).ready ()->
window.model = new Complex()
ko.applyBindings(model)
First, you need to fix your JSON to use : instead of =. You can drop the commas and even the curly braces like so:
[
Name: ''
Subscribe: ''
ScrollOfDish: [0]
,
Name: ''
Subscribe: ''
ScrollOfDish: [0]
]
Here is a working version of the view model code:
$ ->
class Complex
constructor: ->
#complexItems = ko.observableArray()
#getAllComplex()
getAllComplex: ->
$.ajax
type: 'POST'
url: '/Complex/GetAllComplex'
data: {}
dataType: 'json'
contentType: 'json'
success: (res) =>
#complexItems res
window.model = new Complex()
ko.applyBindings model
You can simply use the fat arrow => to bind complexItems to the right this. There are a few stylistic changes I made:
Use -> instead of () ->
Use # instead of this
Use camel case for variable names (complexItems)
Use single quotes for non-interpolated strings
Use $ -> instead of $(document).ready ->
I'd recommend reading this style guide.

Categories

Resources