Javascript object with arrays to search param style query string - javascript

Looking for clean way to convert a javascript object containing arrays as values to a search param compatible query string. Serializing an element from each array before moving to the next index.
Using libraries such as querystring or qs, converts the object just fine, but handles each array independently. Passing the resulting string to the server (which I cannot change) causes an error in handling of the items as each previous value is overwritten by the next. Using any kind of array notation in the query string is not supported. The only option I have not tried is a custom sort function, but seems like it would be worse than writing a custom function to parse the object. Any revision to the object that would generate the expected result is welcome as well.
var qs = require("qs")
var jsobj = {
origString:['abc','123'],
newString:['abcd','1234'],
action:'compare'
}
qs.stringify(jsobj,{encode:false})
qs.stringify(jsobj,{encode:false,indices:false})
qs.stringify(jsobj,{encode:false,indices:false,arrayFormat:'repeat'})
Result returned is
"origString=abc&origString=123&newString=abcd&newString=1234&action=compare"
Result desired would be
"origString=abc&newString=abcd&origString=123&newString=1234&action=compare"

I tried reorder your json:
> var jsobj = [{origString: 'abc', newString: 'abcd' }, {origString: '123',
newString: '1234' }, {action:'compare'}]
> qs.stringify(jsobj,{encode:false})
'0[origString]=abc&0[newString]=abcd&1[origString]=123&1[newString]=1234&2[action]=compare'
But I don't know if this is a good alternative for your problem.

Chalk this up to misunderstanding of the application. After spending some more time with the API I realized my mistake, and as posted above by others, order does no matter. Not sure why my first several attempts failed but the question is 'answered'

Related

appendRow returns [Ljava.lang.Object;# instead of values

I want to copy form submissions over to a different sheet so that the copied data can be edited without affecting the original submissions.
I have the following code:
function copy2(){
var responses = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("from");
var tracker = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("to");
var lastrow = responses.getLastRow();
var col = responses.getLastColumn();
var row = responses.getRange(lastrow, 1, 1, col).getValues();
tracker.appendRow([null,row[0]]);
Using null in appendRow helps you move the info over to the next column. However, it doesn't quite work with the row[0] array. If I remove the null it works fine, but I want the info copied on a column different that the first one.
Why Ljava.lang.Object?
Because you are using the older Rhino runtime that was written in Java. Hence when something unexpected happens you get a glimpse of the infrastructure GAS is built upon. Now, the java.lang.object is a base class in Java from which other objects, including arrays, are derived.
Since the appendRow method signature's only parameter accepts a one-dimensional array of values, your row[0], which contains an array (see what getvalues method returns), made it to the sheet as a string tag indicating that this was an object at runtime.
What to do in Rhino?
All solutions depend on taking [ null ] as your base array and using concat to append the rest of the first row, something like this: [ null ].concat(row[0]). You can also use push with a simple for loop for better performance.
What to do in V80?
As the other answer mentioned, your best bet is the spread syntax. You can also do a push(...row[0]) to avoid concatenation of arrays (since you immediately use and discard the copy resulting from [ null, ...row[0] ]).
0 See official docs on how to migrate to V8 to take advantage of new language features and improved speed.
Explanation:
The approach of using null is clearly a workaround and not a futureproof
solution. Namely, if you want to start pasting from column 4 you
would have to do [null,null,null,...row[0]] which is not the proper
way to do it in my opinion.
I would advice you to get rid of appendRow and null since you
want to paste the data from the second column onwards. Therefore,
use setValues() instead.
Replace:
tracker.appendRow([null,row[0]]);
with:
tracker.getRange(tracker.getLastRow()+1,2,1,row[0].length).setValues(row);
Complete Solution:
function copy2(){
var responses = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("from");
var tracker = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("to");
var lastrow = responses.getLastRow();
var col = responses.getLastColumn();
var row = responses.getRange(lastrow, 1, 1, col).getValues();
tracker.getRange(tracker.getLastRow()+1,2,1,row[0].length).setValues(row);
}
The row variable contains an array so you should use the spread operator with appendRow
Replace:
tracker.appendRow([null,row[0]]);
with:
tracker.appendRow([null,...row[0]]);
Make sure your project is enabled for Chrome V8 runtime.

find value in complex object javascript

Basically I have a complex object that retrieves the GPT API (google publisher tag) with this function:
googletag.pubads().getSlots();
The object value is something like this:
I need to know if there is a way to compare the value of each property with an X value without getting a problem of recursivity (because the object is huge and i need to to that validation several times)
Also, I tried to convert that object into a JSON with JSON.stringify(), and then tried to get the value with a regex, faster, but with this option, I have the problem with Cyclic Object Value.
Any suggestions ?
it's more simple. try it to convert it into an array and later use a filter for comparative with your value.
var objGoogle = {};
var arrayObjectGoogle = [objGoogle];
var filter = arrayObjectGoogle.filter(function(obj){
obj.yourAttr == yourValue; });
this will give you a second array with the values found it. later, index the array for pick up the value do you need.

Turn JSON string with duplicate keys into JSON string arrays

I'm trying to generate a JSON string which will contain all of my filters, but I constantly stuck with duplicate keys. So, I want to find a solution that turns the duplicate keys into a JSON array.
For example, I have this JSON object:
{
"filter-1": "value-1",
"filter-1": "value-2",
"filter-2": "value-3",
"filter-3": "value-4"
}
And I want to turn it into this:
{
"filter-1": ["value-1", "value-2"],
"filter-2": "value-3",
"filter-3": "value-4"
}
Can someone point me in the right direction? I would appreciate solutions in JavaScript but any method would be more than welcome! Thanks in advance!
The duplicate key-pairs are causing overwrite issues.
Javascript objects doesn't allow duplicate keys.
var testObj = JSON.parse('{"filter-1":"value-1","filter-1":"value-2","filter-2":"value-3","filter-3":"value-4"}'); will overwrite the first key-pair (filter-1: value-1) when it parses the second key-pair (filter1: value-2) since both key-pairs have the same key.
However, JSON specification (not Javscript objects) does not specifically mention whether duplicate keys are allowed or not. You may wish to write your own parsing function to handle the duplicate keys.
You will have to change the format of your JSON since keys in JS objects must be unique.
Then you can hard coded or use libraries like jquery or underscorejs to group them out.
https://jsfiddle.net/p5fkjcwt/1/
var objects =
{
0: {"filter": "filter-1", "value":"value-1"},
1: {"filter": "filter-1", "value":"value-2"},
2: {"filter": "filter-2", "value":"value-3"},
3: {"filter": "filter-3", "value":"value-4"}
}
var result = _.groupBy(objects,"filter")
console.log(result)

How to pass a list of xpath values to a function - Array or Object?

I had a question about best practice for passing a list of XML xpath values to a function.
I'm just a beginner programmer and am just learning javascript.
What I want to do is define an object with criteria (done this okay), and a list of results I want back from a query, both of which that can be passed to a function.
The following is working, but I'm thinking that probably sending the xpath as the key in the object is probably not the best idea, with null values. I get back an object from the function with the keys I sent and the values.
var myCriteria = { prospect_id : 98888158, type : 13};
var myResults = { 'total_results':null , 'visitor_activity/id':null };
myResults = pardotQuery(authentication, 'visitorActivity', myCriteria, myResults);
I thought about just passing it in as an array, then converting it into an object that gets returned with keys, and values.
Please advice what would be best.
Thanks.

Deserializing JavaScript object instance

I am working on an app that heavily uses JavaScript. I am attempting to include some object-oriented practices. In this attempt, I have created a basic class like such:
function Item() { this.init(); }
Item.prototype = {
init: function () {
this.data = {
id: 0,
name: "",
description: ""
}
},
save: function() {
alert("Saving...");
$.ajax({
url: getUrl(),
type: "POST",
data: JSON.stringify(this.data),
contentType: "application/json"
});
}
}
I am creating Item instances in my app and then saving them to local storage like such:
Item item = new Item();
window.localStorage.setItem("itemKey", JSON.stringify(item));
On another page, or at another time, I am retriving that item from local storage like such:
var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();
Unfortunately, the "save" function does not seem to get reached. In the console window, there is an error that says:
*save_Click
(anonymous function)
onclick*
I have a hunch that the "(anonymous function)" is the console window's way of saying "calling item.save(), but item is an anonymous type, so I am trying to access an anonymous function". My problem is, I'm not sure how to convert "var item" into an Item class instance again. Can someone please show me?
Short answer:
Functions cannot be serialized into JSON.
Explanation:
JSON is a cross-platform serialization scheme based on a subset of JS literal syntax. This being the case, it can only store certain things. Per http://www.json.org/ :
Objects: An object is an unordered set of name/value pairs. An object begins with { (left brace) and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are separated by , (comma).
Arrays: An array is an ordered collection of values. An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
values: A value can be a string in double quotes, or a number, or true or false or null, or an object or an array. These structures can be nested.
Functions cannot be serialized into JSON because another non-JS platform would not be able to unserialize and use it. Consider the example in reverse. Say I had a PHP object at my server which contained properties and methods. If I serialized that object with PHP's json_encode() and methods were included in the output, how would my JavaScript ever be able to parse and understand PHP code in the methods, let alone use those methods?
What you are seeing in your resulting JSON is the toString() value of the function on the platform you're using. The JSON serilizer calls toString() on anything being serialized which isn't proper for JSON.
I believe your solution is to stop storing instances in JSON/local storage. Rather, save pertinent data for an instance which you set back to a new instance when you need.
I know this question is answered already, however I stumbled upon this by accident and wanted to share a solution to this problem, if anyone is interested.
instead of doing this:
var item = window.localStorage.getItem("itemKey");
item = JSON.parse(item);
item.save();
do something like this:
// get serialized JSON
var itemData = window.localStorage.getItem("itemKey");
//instantiate new Item object
var item = new Item();
// extend item with data
$.extend(item, JSON.parse(itemData));
// this should now work
item.save();
this will work so long as the function you are wanting to call (ie, save()) is prototypal and not an instance method (often times the case, and is indeed the case in the OP's original question.
the $.extend method is a utility method of jquery, but it is trivial to roll your own.
You cant do that, how can javascript possibly knows that item have a save function ? json doesnt allow functions as datas. just read the json spec , you cant save functions.
what you need to do is to create a serialize and deserialize method in the hash you want to stock. that will specifiy what to export and how you can "wake up" an object after parsing the corresponding json string.
You can only store plain Objects in DOMstorages (cookies, urlparams..., everything that needs [de]serialisation through JSON.stringify/JSON.parse). So what you did when sending the ajax data
ajaxsend(this.data);
also applies to string serialisation. You can only store the data, not the instance attributes (like prototype, constructor etc.). So use
savestring(JSON.stringify(item.data));
which is possible because item.data is such a plain Object. And when restoring it, you will only get that plain data Object back. In your case it's easy to reconstruct a Item instance from plain data, because your Items hold their values (only) in a public available property:
var item = new Item;
item.data = JSON.parse(getjsonstring());
Disclaimer
Not a full time time J.S. Developer, answer may have some minor bugs:
Long Boring Explanation
As mentioned by #JAAulde, your object cannot be serialized into JSON, because has functions, the technique that you are using doesn't allow it.
Many people forget or ignore that the objects that are used in an application, may not be exactly the same as saved / restored from storage.
Short & quick Answer
Since you already encapsulate the data members of your object into a single field,
you may want to try something like this:
// create J.S. object from prototype
Item item = new Item();
// assign values as you app. logic requires
item.data.name = "John Doe";
item.data.description = "Cool developer, office ladies, love him";
// encoded item into a JSON style string, not stored yet
var encodedItem = JSON.stringify(item.data)
// store string as a JSON string
window.localStorage.setItem("itemKey", encodedItem);
// do several stuff
// recover item from storage as JSON encoded string
var encodedItem = window.localStorage.getItem("itemKey");
// transform into J.S. object
item.data = JSON.parse(encodedItem);
// do other stuff
Cheers.

Categories

Resources