$.post is changing array of objects to array of arrays - javascript

I try to post via ajax some data. Watch sreenshot1. But jQuery automatic converts object to array. This can be seen in screenshot2 (chrome developer tools).
Data send to $.post:
Data inspect in chrome developer tools:
Edited:
Problems appear in PHP where I expect for Data property to be array of objects:
I want to read data like this:
foreach ($_POST["Data"] as $field)
{
if ($field->Field == "username")
{
...
}
}

It's not really well spelled out in the PHP docs, but this is how it's supposed to work. For instance, the page on request variables has this to say about array-like cookies:
If you wish to assign multiple values to a single cookie variable, you may assign it as an array. For example:
<?php
setcookie("MyCookie[foo]", 'Testing 1', time()+3600);
setcookie("MyCookie[bar]", 'Testing 2', time()+3600);
?>
That will create two separate cookies although MyCookie will now be a single array in your script. If you want to set just one cookie with multiple values, consider using serialize() or explode() on the value first.
In other words, when you send in:
FormData[0][Field]: username
FormData[0][Value]: test3
PHP interprets this as an array of arrays, which looks like this:
array(1) {
[0]=> array(2) {
['Field'] => String(8) "username",
['Value'] => String(5) "test3"
}
}
And you can parse it like so:
foreach ($_POST["Data"] as $field)
{
if ($field['Field'] == "username")
{
...
}
}
Bear in mind that a PHP array is actually an ordered map. In other words, its perfectly suited for storing the key => value data you're passing in with your POST.
You seem to be expecting $_POST to contain simple objects (aka stdClass) and it simply doesn't. Most SOAP helpers in PHP will give you simple object responses (which is a typical blending of behaviors from PHP). See this question for some ideas if you really want to translate every $_POST["Data"] field into an object. But that would be expensive and unnecessary.

The answer is that you are in fact sending an array of objects - not an array of arrays as you've supposed. Here is an example of the data that you are sending to the server:
{
Operations: "Add",
TableName: "users",
Data: [
{
Field: "username",
Value: "test3"
},
{
Field: "someOtherField",
Value: "test4"
},
// ...
]
}
If on the PHP side you are expecting only an array of objects, and not an object containing an array of objects, then you should instead pass options.Parameters.Data, like:
var result = $.post(url, options.Parameters.Data, // ...

Related

Parsing a URL query object in node.js

I need to create a function that will use an object passed in the url. The goal is to update menu items for a restaurant. The query sent will look like this:
?restId=1&posId=1&groups=…&items= [{"id":"000101","price":2500,"desc":"ארוחת ראפ","count":0,"status":0,"type":0,"group":1,"variations":[]},{"id":"000145","price":7980,"desc":"ארוחת בוקר ילדים","count":0,"status":0,"type":1,"group":1,"variations":[{"desc":"LEVEL 1","level":1,"maxNumAllowed":1,"items":[{"id":"000119","price":500,"desc":"ספריבס כבש טרי","count":0,"type":0,"group":1,"variations":[]},{"id":"000117","price":0,"desc":"פילה עוף טרי","count":0,"type":0,"group":1,"variations":[]},{"id":"000166","price":0,"desc":"שישליק הודו טרי","count":0,"type":0,"group":1,"variations":[]}]&pizzas=[{"id":"100250","desc":"מגש משפחתית","slices":4,"price":6400,"count":1,"group":3,"toppingPolicy":[{"id":"100112","desc":"תוספת גבינה","pricing":[{"slicesCount":1,"price":200},{"slicesCount":2,"price":400},{"slicesCount":3,"price":600},{"slicesCount":4,"price":800}]},{"id":"100111","desc":"ללא גבינה","pricing":[{"slicesCount":1,"price":0},{"slicesCount":2,"price":0},{"slicesCount":3,"price":0},{"slicesCount":4,"price":0}]},{"id":"100110","desc":"ללא רוטב","pricing":[{"slicesCount":1,"price":0},{"slicesCount":2,"price":0},{"slicesCount":3,"price":0},{"slicesCount":4,"price":0}]}],"discountable":true}]
When I run const queryObject = url.parse(req.url,true).query; it prints:
[Object: null prototype] {
restId: '1',
posId: '1',
groups: '…',
items: ' [{"id":"000101","price":2500,"desc":"ארוחת ראפ","count":0,"status":0,"type":0,"group":1,"variations":[]},{"id":"000145","price":7980,"desc":"ארוחת בוקר ילדים","count":0,"status":0,"type":1,"group":1,"variations":[{"desc":"LEVEL 1","level":1,"maxNumAllowed":1,"items":[{"id":"000119","price":500,"desc":"ספריבס כבש טרי","count":0,"type":0,"group":1,"variations":[]},{"id":"000117","price":0,"desc":"פילה עוף טרי","count":0,"type":0,"group":1,"variations":[]},{"id":"000166","price":0,"desc":"שישליק הודו טרי","count":0,"type":0,"group":1,"variations":[]}]',
pizzas: '[{"id":"100250","desc":"מגש משפחתית","slices":4,"price":6400,"count":1,"group":3,"toppingPolicy":[{"id":"100112","desc":"תוספת גבינה","pricing":[{"slicesCount":1,"price":200},{"slicesCount":2,"price":400},{"slicesCount":3,"price":600},{"slicesCount":4,"price":800}]},{"id":"100111","desc":"ללא גבינה","pricing":[{"slicesCount":1,"price":0},{"slicesCount":2,"price":0},{"slicesCount":3,"price":0},{"slicesCount":4,"price":0}]},{"id":"100110","desc":"ללא רוטב","pricing":[{"slicesCount":1,"price":0},{"slicesCount":2,"price":0},{"slicesCount":3,"price":0},{"slicesCount":4,"price":0}]}],"discountable":true}]'
}
My problem is that I cannot access any of the values in items. I was given this url, so I cannot change it at all. How can I parse items in order to access the values?
The value of items and pizzas are both JSON formatted strings. You have to parse them to access the contained data. This is accomplished by calling JSON.parse()
So in your case, to access items, you could do the following:
const items = JSON.parse(queryObject.items)
The only problem you have now is that items isn't actually a valid JSON string. It's missing four closing tags }]}] at the end. I'm not sure if that's a transcription error or if you're actually getting a malformed URL, but that will cause you issues if the URL in your question is accurate.

How do handle empty arrays when serializing only altered form elements

I have a form that consists of a number of multi-select fields. Each select has a unique ID, and are named accordingly:
values[foobar1][]
values[foobar2][]
values[foobar3][]
... etc.
This form could potentially contain hundreds of these fields, and so is paged by ajax. The result of that is that there is no guarantee that all records are going to available at once at the front end. Therefore, it is impossible for me to submit the entire form. I do, however, have access to the entire list of records server-side.
My solution to this was to watch for changes in the form fields and, for every field that is changed, store the values in an array to keep track of just the altered field values. So if you make a change to just foobar2, the resulting serialized array that is sent to the server will look like this:
0: Object {
name: "values[foobar2][]"
value: "thevalue1"
},
1: Object {
name: "values[foobar2][]"
value: "thevalue3"
}
So this works fine except for, as you may have guessed, when the select multiple is emptied. No matter what format I use for storing the altered values, be it arraySerialization of each field or as an associative array, when I pass my array to $.param() for the ajax request the resulting serialized string contains no trace of the empty value. So there is no way for the server to determine that the value has been emptied.
Can anyone suggest a way of either passing the data to the server so that the empt(ied) array remains intact, or another way of dealing with the initial problem.
Thanks in advance!
You want to calculate the diff between current and previous state, send the change to the server, and apply it to the data.
You can do so using the JSON patch standard (rfc6902).
JSON Patch is a format for describing changes to a JSON document. It
can be used to avoid sending a whole document when only a part has
changed. When used in combination with the HTTP PATCH method it allows
partial updates for HTTP APIs in a standards compliant way.
To create the diff you can use an NPM module, such as jiff. A diff is set a of patching commands, that can transform a JSON document. For example:
[
{ "op": "replace", "path": "/values/foobar2/", "value": ["thevalue1"] },
{ "op": "remove", "path": "/values/foobar2/"}
]
You send the diff to the server, and then use a server module, such as php-jsonpatch, to apply the patch to the current data on the server.
Create a single object for all select field values you can use localStorage or sessionStorage to store it. Since the form is in a lot of pages and you use ajax to get each select field. Place the selected values of each field in an array. Creating an object like this is the idea.
{
formValues: {
foobar1: {
values: ["thevalue1","thevalue2"]
},
foobar2: {
values: ["thevalue3"]
},
...
foobarN: {
values: []
}
}
}
Every time you update a select vield value or values make sure to update the localStorage saved value. e.g.
var valuesObject = {
formValues: {
foobar1: {
values: ["thevalue1","thevalue2"]
},
foobar2: {
values: ["thevalue3"]
},
foobar3: {
values: []
}
}
}
// Put the object into storage
localStorage.setItem('valuesObject', JSON.stringify(valuesObject));
// Retrieve the object from storage
var valuesObjectA = localStorage.getItem('valuesObject');
//console.log('valuesObject: ', JSON.parse(valuesObjectA));
// post your data
$.post( "ajax.php", valuesObjectA ).done(function( data ) {
alert( "Data Loaded: " + data );
}).fail(function() {
console.log( "error" );
});
Sample fiddle

object has no method push in node js

I am trying to append the user details from the registration form to the json file so that the user-details can be used for authentication. the problem is i am not able append to the json file in correct format.The code i have tried so far is,
var filename= "./user_login.json";
var contents = fs.readFileSync(filename);
var jsonContent = JSON.parse(contents);
//sample data
var data =[
{
"try" : "till success"
}
];
jsonContent.push(data);
fs.writeFileSync(filename,jsonContent);
I have tried different methods that i found by googling and nothing worked so far. I want the data to be stored in correct format. Most of the times i got this error like object has no push function. So what is the alternative to that?
The correct format i am looking for is ,
[
user1-details : {
//user1 details
},
user2-deatils : {
}//So on
]
Object has no push function, arrays do. Your json is invalid too, it should be an array:
[ // here
{
//user1 details
},
{
//So on
}
] // and here
Now, you can use push(). However, data is an array, if you want an array of objects in your json file, it should be a simple object:
var data = {
"try" : "till success"
};
You also have to stringify the object before writing it back to the file:
fs.writeFileSync(filename, JSON.stringify(jsonContent));
You should consider using something like node-json-db, it will take care of reading/writing the file(s) and it gives you helper functions (save(), push()...).

How do I return arbitrary JSON objects to a jQuery Autocomplete list?

jQuery part:
I have a jQuery UI 1.8 Autocomplete form that fetches remote JSON data from a Rails controller.
$('input#test').autocomplete({
source: function( request, response ) {
$.getJSON(
"<%= find_stuff_url(:format => :json) %>",
request,
function(data){
console.log(data);
function(data) {
$.map(data, function(item) {
return {
"label" : item.control_point.label,
"value" : item.control_point.geonames_uri
}
});
});
},
minLength: 2,
select: function( event, ui ) {
// ...
}
});
… what I get returned:
This Rails controller just returns an array of Objects (actually, ActiveRecord instances), serialized into JSON. I would like to use this data to populate the Autocomplete list. Right now, what I receive is an array of serialized ActiveRecord objects – for example one of these objects could be:
Object
control_point: Object
geonames_uri: "http://sws.geonames.org/5128581/"
label: "New York (US)"
lat: "40.7142691"
lng: "-74.0059729"
map_id: 1
name: "New York City"
What I need:
However, jQuery Autocomplete probably wants a JSON array of objects that carry id and label to populate its list — yet I don't have these. This is what the documentation says:
A response callback, which expects a single argument to contain the data to suggest to the user. This data […] can be in any of the formats described above for simple local data (String-Array or Object-Array with label/value/both properties).
I don't quite understand what's meant by "String-Array or Object-Array with label/value/both" properties.
In this example, my output would be a list of those control_point Objects, shown like:
label: "New York (US)", value: <the geonames_uri>
label: "New York (Somewhere else)", value: <another geonames_uri>
…
I tried to adapt the code from the documentation using $.map, but it doesn't seem to work (i.e. the autocomplete shows nothing).
How do I pass an arbitrary JSON object to jQuery Autocomplete, so it shows a list of results? More explicitly: What do I have to put in function(data){}?
The documentation (at the same link you posted) explains what is meant by the terms String-Array and Object-Array:
The local data can be a simple Array of Strings, or it contains
Objects for each item in the array, with either a label or value
property or both. The label property is displayed in the suggestion
menu. The value will be inserted into the input element after the user
selected something from the menu. If just one property is specified,
it will be used for both, eg. if you provide only value-properties,
the value will also be used as the label.
So at the end of the day, it's either a String-Array: ["value1", "value2", ...] or an Object-Array:
[
{ label:"First Value", value:"value1" },
{ label:"Second Value", value:"value2" },
...
]
You can choose to either make the required server side changes to serialise the data to look appropriate, or map it client side, as in this example. Either way the end result should be one of the above formats.
So, for example, something like this:
function(data) {
response( $.map(data, function(item) {
return {
"label" : item.control_point.label,
"value" : item.control_point.geonames_uri
}
}));
This is something you'll want to do server-side, i.e. in Ruby on Rails. You could to this:
Give your model (ActiveRecord entity, whatever) a method toAutocompleteResult that returns an Object with just the label and value properties.
In your controller (return_stuff_url?), loop through your result set, call toAutocompleteResult() on them and put the results in an Array of sorts.
Convert the Array to JSON and return it.
I'm not a RoR developer, so I can't give you specific code. But this should be pretty easy to do in any OO language.
Edit: by the way, a JSON string array looks like this:
["String 1", "String 2", "String 3"]
And a JSON Object array would look like this:
[
{ "label" : "Label 1", "value": "Value 1" },
{ "label" : "Label 2", "value": "Value 2" }
]
You need something like this on the server
def my_autocomplete_controller_method
q = params[:term]
records = Record.find_by_whatever q
records.map { |record| {label: record.your_label, value: record.your_value} }
end
On the client (coffescript):
$find_field.autocomplete
source: /path_to_controller_method

Getting started with extJS

I don't get what I'm doing wrong.
I'm trying to populate a form from a JSON string from the server and it doesn't work. I get nothing at all back. I examine the object and it's undefined. I've been beating my head against the wall for 3 days now. I need a simple example that works and I'll build from there.
Here's the simple example that I've been trying to use:
var messages = new Ext.data.JsonStore({
url: '/user/' + user_id,
method: 'GET',
root: 'user',
fields: [
{name: 'user_id'},
{name: 'first_name'}
],
listeners: {
load: messagesLoaded
}
});
messages.load();
function messagesLoaded(messages) {
console.log(messages);
}
Here's my JSON string:
{"success":"true","user":{"user_id":"2","first_name":"Test","last_name":"Test","email":null,"password":null,"city_id":"6379","birth_date":"2009-06-09","gender":"F","created_on":"2009-06-01 17:21:07","updated_on":"2009-06-14 17:20:14","active":"Y","cuisine_id":null}}
I really don't see what I'm doing wrong, but my JSON string isn't loading. Thanks!
Ok so you're almost there, but one problem. The root ("user" in this case) has to be an array. Even if it's an array with only 1 object. Ext.data.JsonReader (the default reader for a Ext.data.JsonStore) only accepts an array of results.
So your javascript looks just fine, but the JSON object returned by the server needs to look more like this.
{
"success":"true",
"user": [{
"user_id":"2",
"first_name":"Test",
"last_name":"Test",
"email":null,
"password":null,
"city_id":"6379",
"birth_date":"2009-06-09",
"gender":"F",
"created_on":"2009-06-01 17:21:07",
"updated_on":"2009-06-14 17:20:14",
"active":"Y",
"cuisine_id":null
}]
}
One more thing, consoloe.logging your store object will produce something like [Object] in Firebug... not too useful. You should either console.dir it, or log your actual data instead.
One comment about loading your form, once you get past loading your JSON (even though this example does not show that). Make sure your form is actually rendered before trying to load it with data, e.g. if trying to use something like form.loadRecord. Otherwise you'll end up with an empty form and no errors.

Categories

Resources