Objects with and without quotation marks - javascript

Edit: using google apps script, these are objects that are passed back from their functions. When I say logged I mean the result of the return function is logged in GAS.
I have objects that serve as profiles for a larger script, and I was trying to generate a larger profile programmatically.
When called and logged:
[ { name: "a1",
functionName:"functionA",
options:{something:"a1run"}
},
{ name: "a2",
functionName:"functionA",
options:{something:"a2run"}
},
{ name: "a3",
functionName:"functionA",
options:{something:"a3run"}
}
]
Shows up in the log as this:
[{
functionName = functionA,
name = a1,
options = {
something = a1run
}
},
}, {
functionName = functionA,
name = a2,
options = {
something = a2run
}
}, {
functionName = functionA,
name = a3,
options = {
something = a3run
}
}]
you'll note that all of the quotation marks disappeared.
Yet when I call an almost identical function where I generated each part of the object with a for loop (this)
var s1 = "";
for (var i=0; i<5;i++)
{
var newString = '';
newString += '{ name: "a'+i+'",';
newString += 'functionName: "functionA",';
newString += 'options:{something: "a'+i+'run"} },';
s1+= newString;
}//for loop
The logged result of the function is this:
[{
name: "a0",
functionName: "functionA",
options: {
something: "a0run"
}
}, {
name: "a1",
functionName: "functionA",
options: {
something: "a1run"
}
}, {
name: "a2",
functionName: "functionA",
options: {
something: "a2run"
}
}, {
name: "a3",
functionName: "functionA",
options: {
something: "a3run"
}
}, {
name: "a4",
functionName: "functionA",
options: {
something: "a4run"
}
}, ]
This is a problem because the initial formatting does work as a profile, and the second one does not. What aspect of JavaScript objects do I need to understand? I didn't think it would make a difference because this object goes through a JSON.stringify when it is used but I was wrong.
My question isn't just how I change it so that it is processed the same way, but why one is being treated differently from the other.

This is not the correct way of creating a JSON array
you should do something like this and forget about creating a string of JSON array
let output = [];
for (var i = 0; i < 5; i++) {
output.push({
name: "a" + i,
functionName: "functionA",
options: {
something: "a" + i + "run"
}
});
}
console.log(output);

Instead of using Logger or the Google Apps Script built-id debugger to "print" your JSON in order to debug it if you are able to use Stackdriver use it or use the HTML Service to print the JSON object to your web browser console instead.
The above becase the Log view (View > Logs), as you already found, not always print JSON objects correctly.
If you want to use Logger, first you should convert to JSON object to string. In most cases using JSON.stringify(...) will work fine.
References
https://json.org/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON

Related

Filter Array Using Partial String Match in Javascript

I have an array of objects where the value I need to filter on is buried in a long string. Array looks like:
{
"data": {
"value": "{\"cols\":[\"parent_sku\"],\"label\":\"Style\",\"description\":\"Enter Style.\",\"placeholderText\":\"Style 10110120103\"}",
"partnerId": 1
}
},
So if I wanted to grab all the partnerId objects where value includes parent_sku how would I do that?
console.log(data.value.includes('parent_sku') returns cannot read property 'includes' of null.
EDIT:
Didn't think this mattered, but judging by responses, seems it does. Here's the full response object:
Response body: {
"data": {
"configurationByCode": [
{
"data": {
"value": "{\"cols\":[\"parent_sku\"],\"label\":\"Style\",\"description\":\"Enter Style.\",\"placeholderText\":\"Style 10110120103\"}",
"partnerId": 1
}
}
I'm passing that into a re-usable function for filtering arrays:
const parentSkuPartners = filterArray(res.body.data.configurationByCode, 'parent_sku');
Function:
function filterArray(array, filterList) {
const newList = [];
for (let i = 0; i < array.length; i += 1) {
console.log('LOG', array[i].data.value.includes('parent_sku');
}
}
The problem is somewhere else. The code you've tried should work to find if a value contains a string – I've added it the snippet below and you'll see it works.
The issue is how you are accessing data and data.value. The error message clearly states that it believes that data.value is null. We would need to see the code around it to be able to figure out what the problem is. Try just logging to console the value of data before you run the includes function.
const data = {
"value": "{\"cols\":[\"parent_sku\"],\"label\":\"Style\",\"description\":\"Enter Style.\",\"placeholderText\":\"Style 10110120103\"}", "partnerId": 1
};
console.log('includes?', data.value.includes('parent_sku'));
You can use data.value.includes('parent_sku') as you have suggested. The issue here is that your object is nested inside an unnamed object.
try:
"data": {
"value": "{\"cols\":[\"parent_sku\"],\"label\":\"Style\",\"description\":\"Enter Style.\",\"placeholderText\":\"Style 10110120103\"}",
"partnerId": 1
}
The problem was some of the values for value were null. Adding an extra conditional fixed it:
if (array[i].data.value !== null) {
Use lodash includes, and lodash filter like
let configurationByCode = [{
data: {
value: {
cols:["parent_sku"],
label:"Style",
description:"Enter Style.",
placeholderText:"Style 10110120103"
},
"partnerId": 1
}
}, {
data: {
value: {
cols:["nothing"],
label:"Style",
description:"Enter Style.",
placeholderText:"Style 10110120103"
},
"partnerId": 2
}
}];
let wantedData = _.filter(configurationByCode, (config) => {
return _.includes(config.data.value.cols, 'parent_sku');
});
console.log( wantedData );
https://jsfiddle.net/76cndsp2/

Unable to render tree like structure in Angular?

Hi I am developing web application in Angular 5. I am trying to display tree like structure. I am following the
https://github.com/500tech/angular-tree-component/blob/master/example/cli/src/app/async/async.component.ts and
https://angular2-tree.readme.io/docs/async-data-1
In the above example they have given some data and my application works with it. In real time I am using some other data and converting it to exactly the format in the example they have given.
Below is my example.
let results = JSON.parse('{"userid":"e75792f8-cfea-460e-aca2-07a778c92a7c","tenantid":"00000000-0000-0000-0000-000000000000","username":"karthik","emailaddress":"john#krsars.onmicrosoft.com","isallowed":false,"userroles":[{"userroleid":"b81e63d1-09da-4aa0-af69-0f086ddb20b4","userid":"e75792f8-cfea-460e-aca2-07a778c92a7c","roleid":"85d2f668-f523-4b64-b177-b1a78db74234","tenantappid":1,"validfrom":"2018-01-24T00:00:00","validto":"2018-01-24T00:00:00","isactive":true}]}');
for (const key in results) {
if (results[key] instanceof Array) {
const containerTyp2 = {name: '', hasChildren: false,};
containerTyp2.name = key;
containerTyp2.hasChildren = true;
this.nodes.push(containerTyp2);
} else {
const object = {name: ''};
const containerTyp1 = {name: '', children: []};
object.name = results[key];
containerTyp1.name = key;
containerTyp1.children.push(object);
this.nodes.push(containerTyp1);
}
}
console.log(this.nodes);
Below is the sample data from application example.
this.nodes = [
{
name: 'root1',
children: [
{ name: 'child1' }
]
},
{
name: 'root2',
hasChildren: true
},
{
name: 'root3'
}
];
I am converting my raw data to same format to the example above. When I display both data in console both looks similar except id field. Whenever i display example data, I can see id field get added with random value but explicitly they are not adding. Below is the console of example data.
Below is the console of raw data.
Can someone help me to figure out the issue? I am not able to identify what is the reason not to display raw data. Any help would be appreciated. Thank you.
I fixed this issue by adding below line at the end of for loop.
let results=data;
for (const key in results) {
if (results[key] instanceof Array) {
const containerTyp2 = {name: '', hasChildren: false,};
containerTyp2.name = key;
containerTyp2.hasChildren = true;
this.nodes.push(containerTyp2);
} else {
const object = {name: ''};
const containerTyp1 = {name: '', children: []};
object.name = results[key];
containerTyp1.name = key;
containerTyp1.children.push(object);
this.nodes.push(containerTyp1);
}
this.tree.treeModel.update();

Create tags object from array in mongo collection for Select2 options

I have a mongo collection with a array field called 'tags'. What I want to do is create a single object that stores all of the various tags with a label and value. The end result should be an object I can use in a Select2 field in a Meteor application to create the results options. I have gotten close, but all of my solutions have not worked and are super ugly (read: not functional javascript)
Here is a sample document:
{
"_id": "sjkjladlj",
"title": "Coldplay is Cool",
"tags": ["music", "yuppie"]
}
Now the end result I would like is:
[
{
value: "music",
label: "music"
},
{
value: "yuppies",
label: "yuppies"
},
{
value: "Some tag from another doc"
label: "Some tag from another doc"
}
]
Any ideas?
Here is the closest I have gotten.
options: function() {
tagsArray = [];
ca = Notes.find({}, {tags: 1}).fetch();
ca.forEach(function(it) {
result = {};
result = it.tags;
tagsArray.push(result);
});
console.log(tagsArray);
return tagsArray;
}
}
you can try with aggregation pipeline like this
db.colleaction.aggregate([{$project:{_id:0,tags:1}},{$unwind:"$tags"},{$project:{"value":"$tags","lable":"$tags"}}])
Update. As soon as I posted I realized I simply need to add a inner loop. Its ugly, but it works.
options: function() {
tagsArray = [];
ca = Notes.find({}, {tags: 1}).fetch();
ca.forEach(function(it) {
result = {};
result = it.tags;
result.forEach(function(child){
inner = {};
inner.value = child;
inner.label = child;
tagsArray.push(inner);
});
});
console.log(tagsArray);
return tagsArray;
}

Create Javascript objects from a template

I want to create a javascript object from a template. The problem is I don't know what the template is going to look like beforehand. As a simple example, if I had the template function
template = function (data) {
return {
title: data.title
}
}
then I could run template({ title: "Steve" }) and get back the object
{ title: "Steve" }
Because data.title is not evaluated until I call the template function. But I'm constructing an object based on user input where the field names are not known beforehand and could be deeply nested anywhere in the object.
If I define the object that is returned beforehand then the data.title field in the example would already be evaluated and wouldn't use the input data. For example, I want to be able to define the template object like
obj = { title: this.title }
then redefine the template as
template = function () {
return obj
}
and call template.call({title:"Steve"}). But currently I get back
{ title: undefined }
because this.title was already evaluated when I defined obj. Maybe I'm approaching this the wrong way, because I keep coming to the conclusion that I'd have to modify the function by stringifying it, modifying the string to include the unevaluated code this.title and creating a new function from the string. But that seems like a plain awful idea.
And traversing the object looking for special values to replace seems expensive and complicated. I also looked for some sort of javascript object templating library but didn't find anything.
EDIT: To make it more clear that the input data and the template structure won't necessarily match, I may want have a template that looks like
template = function (data) {
return {
name: "Alfred",
stats: {
age: 32,
position: {
level: 10,
title: data.title
}
}
}
}
and call template({title:"Manager"}) to get
{
"name": "Alfred",
"stats": {
"age": 32,
"position": {
"level": 10,
"title": "Manager"
}
}
}
So I've managed to solve this by (ab)using functions as metadata to mark the values that should be replaced in the template. This is made possible by two things:
I only need valid JSON values, so I can safely say that functions aren't literal user input
JSON.stringify has a replacer parameter which will traverse the object and can be used to pass the input data to the template
Using a template generator like this
var templateMaker = function (object) {
return function (context) {
var replacer = function (key, val) {
if (typeof val === 'function') {
return context[val()]
}
return val;
}
return JSON.parse(JSON.stringify(obj, replacer))
}
}
I create a template object, replacing field names with functions that return the field name
var obj = {
name: "Alfred",
stats: {
age: 32,
position: {
title: function () { return 'title' },
level: function () { return 'level' }
}
}
}
then I create the template function, define my input, and render it to an object
var template = templateMaker(obj);
var data = {
title: "Manager",
level: 10
}
var rendered = template(data);
and magically, the object output looks like
{
"name": "Alfred",
"stats": {
"age": 32,
"position": {
"title": "Manager",
"level": 10
}
}
}
Maybe template engines like Mustache would help you with this.
You can define your object template in string:
var template = '{ title: {{title}} }';
then render it with the data, and convert it to json:
var data = {title: 'I am title'};
var obj = JSON.parse(Mustache.render(template, data));
UPDATE:
I read your updated example, here is the corresponding example:
var template = JSON.stringify({
name: "Alfred",
stats: {
age: 32,
position: {
level: 10,
title: '{{title}}'
}
}
});
var data = {title: 'I am title'};
var obj = JSON.parse(Mustache.render(template, data));
obj.stats.position.title == "I am title";

prototype JSON to Object

The following is part of a JSON string returned from the server:
{
col1: {
caption: 'Workspace',
combodata: {
c_0: {
id: 0,
value: 'Filter...'
},
c_1: {
id: 1,
value: 'Tax'
},
c_2: {
id: 2,
value: 'HR'
}
}
}
}
After eval, I can access .caption, and .combodata is visible in Firebug as an object, with c_0 and c_1 visible as objects inside .combodata, with id and value in both c_0 and c_1.
How do I step through each object in .combodata? I tried .combodata.each(c), but that throws an exception. I won't know the names of the objects in .combodata during run time.
You can use a regular for loop for that:
for(var key in obj.col1.combodata) {
var combo_obj = obj.col1.combodata[key];
...
}
Can I suggest that you do not eval() the JSON that's returned? What you should be doing is:
var jsondata = { ... };
var obj = JSON.parse(jsondata);
The reason is because eval'ing a string can be dangerous. Imagine if your JSON data looked like this:
"{ some json data here }; alert(document.cookie)"
When you eval that, the users cookie is displayed to them. Now think what happens if instead of alert, that cookie is posted to an attackers URL. They now have access to that users account if such exists.
if
var result = {col1: { caption: 'Workspace',combodata: {c_0: {id: 0,value: 'Filter...'},c_1: {id: 1, value: 'Tax'},c_2: {id: 2, value: 'HR'}}}};
then
for ( i in result.col1.combodata ) {
var item = result.col1.combodata[i];
//Do stuff with item
}
I have found the following to work as well and will use this:
Object.values(col1.combodata).each(function(c2) {
id = c2.id;
});

Categories

Resources