How to Create javascript json multidimensional tree from flat data - javascript

Hello guys I have a problem creating JSON tree from input form. Imagine you have one section of fields and then dynamically more sections are added. To be more precise, I am talking about switch properties. I just dont know how to add key as new array and then put there more properties with values. Here is the code I am fighting with.
//FIRST section with just basic info about switch
function generateNewSwitchInDB() {
var portInfo = [];
$('#myModal').find('#inputs').find('input').each(function(){
var switchProperty = $(this)[0].id;
portInfo[switchProperty] = $(this)[0].value;
});
//SECOND section dynamically loop through new created sections and grab input id and input value
portInfo.push({'portSlots' : 'portSlot'});
$('#myModal').find('.ports').each(function(){
portInfo[0]['portSlots'][$(this)[0].id] = $(this)[0].id;
$(this).find('input').each(function(){
var placeHolder = $(this)[0].placeholder;
portInfo[0]['portSlots']['0'][placeHolder] = $(this)[0].value;
});
});
console.log(portInfo);
}
What i want to achieve should look like this, but I cant figure out how to push there new key and to that key add properties.
{
'SwitchBasicInfo':{
'location':'Munich',
'vendor':'Cisco',
'hostname':'Switch123',
},
'Slots':{
'slot1':{
'numberOfEthernetPorts':'20',
'numberOfSerialPorts':'50',
'numberOfConsolePorts':'1',
},
'slot2':{
'numberOfEthernetPorts':'50',
'numberOfSerialPorts':'2',
'numberOfConsolePorts':'1',
},
'slot3':{
'numberOfEthernetPorts':'100',
'numberOfSerialPorts':'20',
'numberOfConsolePorts':'1',
},
}
}

Ok, I figured that out, every new level must begin with an array.
First section with basic data
var newSwitchData = new Object();
newSwitchData = {'switchBasicInfo': {}};
newSwitchData.switchBasicInfo['switchProperty'] = $(this)[0].value;
Dynamic sections within foreach loop
newSwitchData.portSlots = {};
newSwitchData.portSlots['slotId'] = {};
newSwitchData.portSlots['slotId']['placeHolder'] = $(this)[0].value;

Related

How to automatically add questions in a Google Form based on columns on Google Sheets? [duplicate]

I'm new with Google scripts and now I have to make a form with a list of choices. These choices should be picked up from the Google sheet.
So the first question is how to chose only unique values from some range of my spreadsheet?
The second is how to pass this list so that they will be the items in the list?
The code I've tried is:
function getMembranesList() {
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/......");
var itemList = ss.getSheetByName('Answers').getRange("Q1:Q").getValues();
var form = FormApp.getActiveForm();
var item = form.addListItem()
item.setTitle('test question');
item.createChoice(itemList);
}
Looking at the methods available to populate the ListItem, you have to choose one and set your data up so it matches the expected input. For my example, I chose the setChoiceValues method, which looks for an array. So I have to manipulate the items into an array.
One thing the getRange.getValues() method does NOT get you is how many non-blank items are returned in the list. I used this quick way to get a count of those items, so I have a maximum bound for my loops. Then, I formed the itemArray and added only the non-blank items to it.
After that, it's just a matter of creating the ListItem and adding the values:
function getMembranesList() {
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/...");
var itemList = ss.getSheetByName('Answers').getRange("Q1:Q").getValues();
var itemCount = itemList.filter(String).length;
var itemArray = [];
for (var i = 0; i < itemCount; i++) {
itemArray[i] = itemList[i];
}
var form = FormApp.getActiveForm();
var item = form.addListItem();
item.setTitle('test question');
item.setChoiceValues(itemArray);
}

How to document merge a parent record and all of its child records

I'm creating a document merge (mail merge) from Google App Maker to a Google Document template. I can do so successfully when merging one single record, but how do you merge several records into the one document?
I have an purchase_orders parent record which has several purchase_order_line_items child records but I can't seem to get all of these records into a single document merge.
A similar question (Document Merge with Google App Maker) was asked by by Johan W with a comprehensive answer by Markus Malessa and Pavel Shkleinik (thank you!). However, it only caters for cases when you are merging one single record.
I have tried to build on their answer by using a second for loop to get the data of all associated child records. The script runs but only seems to merge the first child record; not all of them.
Here is an example of the server-side code I've tried to use:
function Export(key, key2) {
// Get the parent record by its key, which was passed by the first parameter above
var record = app.models.Purchase_Orders.getRecord(key);
// Get the first child record by its key, which was passed by the second parameter above
var childRecord = app.models.Purchase_Order_Line_Items.getRecord(key2);
// Get the Google Document which will be used as a template for this merge
var templateId = '1Xbt8camqHJYrhBnx0a6G2-RvTvybqU0PclHifcdiLLA';
//Set the filename of the new merge document to be created
var filename = 'Document for Customer ' + new Date();
//Make a copy of the template to use as the merge document
var copyFile = DriveApp.getFileById(templateId).makeCopy(filename);
//Get the Google Docs ID of the newly created merge document
var copyDoc = DocumentApp.openById(copyFile.getId());
var copyBody = copyDoc.getBody();
// Replace the field names in the template with the field data from the parent record
var fields = app.metadata.models.Purchase_Orders.fields;
for (var i in fields) {
console.log(i);
var text = '<<' + fields[i].name + '>>';
var data = record[fields[i].name];
if (data !== null) {
copyBody.replaceText(text, data);
} else {
// do nothing
}
}
// Replace the field names in the template with the field data from the child records
childFields = app.metadata.models.Purchase_Order_Line_Items.fields;
for (i in childFields) {
console.log(i);
var childtext = '<<' + childFields[i].name + '>>';
var childdata = childRecord[childFields[i].name];
if (childdata !== null) {
copyBody.replaceText(childtext, childdata);
} else {
// do nothing
}
}
}
How can I improve my code so that all associated child records are merged into a single document?
How can I set up my Google Document template to cater for any number of child records?
Rather than passing in the child record key via a second parameter, I would suggest just passing in the parent key and then changing your function as follows:
function Export(key) {
// Get the parent record by its key, which was passed by the first parameter above
var record = app.models.Purchase_Orders.getRecord(key);
// Get the first child record by its key, which was passed by the second parameter above
var childRecords = record.Purchase_Order_Line_Items;
// Get the Google Document which will be used as a template for this merge
var templateId = '1Xbt8camqHJYrhBnx0a6G2-RvTvybqU0PclHifcdiLLA';
//Set the filename of the new merge document to be created
var filename = 'Document for Customer ' + new Date();
//Make a copy of the template to use as the merge document
var copyFile = DriveApp.getFileById(templateId).makeCopy(filename);
//Get the Google Docs ID of the newly created merge document
var copyDoc = DocumentApp.openById(copyFile.getId());
var copyBody = copyDoc.getBody();
// Replace the field names in the template with the field data from the parent record
var fields = app.metadata.models.Purchase_Orders.fields;
for (var i in fields) {
console.log(i);
var text = '<<' + fields[i].name + '>>';
var data = record[fields[i].name];
if (data !== null) {
copyBody.replaceText(text, data);
} else {
// do nothing
}
}
// Replace the field names in the template with the field data from the child records
var childFields = app.metadata.models.Purchase_Order_Line_Items.fields;
var table = [];
var tableheader = [];
for (i in childFields) {
console.log(i);
tableheader.push(childFields[i].displayName);
}
table.push(tableheader);
for (i in childRecords) {
var data = [];
for (var j in childFields) {
data.push(childRecords[i][childFields[j].name]);
}
table.push(data);
}
copyBody.appendTable(table);
The table building is based on a 2D array and the documentation is here https://developers.google.com/apps-script/reference/document/table. But you will also need to remove your prebuilt table in favor of just appending a table instead. This way you are not dependent on the quantity of child records being fixed like they currently are in your document template. Also, the variable for childRecords may or may not work, I have not tested this since I am unsure if prefetch works in conjunction with .getRecord(key). This may require some additional testing but hopefully this will provide enough guidance.
Thought I would add this as an alternative. Lets say you keep your table but remove all the rows with exception for the header row then you could still use DocumentApp service to add your rows to the table like so:
var tableheaderfieldnames = ['Quantity_for_PO', 'Inventory_Item.id', 'Unit_Price']; //set a fixed table header with the field names, uncertain if the table header for the related inventory item will work or not
var table = copyBody.getTables()[0];
for (i in childRecords) {
var row = table.appendRow();
for (var j in tableheaderfieldnames) {
row.appendTableCell(childRecords[i][tableheaderfieldnames[j]]);
}
}
Keep in mind that AM does not allow you to use FK references, so for your inventory item that appears to use a fk field you may need to tinker around with setting the proper name reference for when you are trying to fill in the item in your table.

How to implement a map for array of strings in javascript

My code :
var appsAndScopes=[
['1',['A','B','C','D']],
['2 ',['E','F','G','H']],
['3',['I']],
['4',['J']]
];
function getAllElements(id){return document.getElementById(id);}
function buildDropdowns(){
var applications=getAllElements('application').options; //Gets all applications names from appsAndScopes array.
for(var applicationsIndex=0;applicationsIndex<appsAndScopes.length;applicationsIndex++){
applications[applications.length]=new Option(appsAndScopes[applicationsIndex][0],appsAndScopes[applicationsIndex][0]);
}
getAllElements('application').onchange=function(){
this.blur();
var currentApplication=this.value;
if(!currentApplication){return;}
var scopes=getAllElements('scope').options;
scopes.length=1;
for(var scopesIndex=0;scopesIndex<appsAndScopes.length;scopesIndex++){
if(appsAndScopes[scopesIndex][0]!==currentApplication){continue;}
else{
var temp=appsAndScopes[scopesIndex][1];
for(var valueIndex=0;valueIndex<temp.length;valueIndex++){
scopes[scopes.length]=new Option(temp[valueIndex],temp[valueIndex]);
}
break;
}
}
}
}
$(function() {
buildDropdowns();
});
In this code, I am generating dynamic drop downs (i.e. dependent drop downs). This code is working fine. It's using 2d array to populate the values of drop downs. I want to implement a map instead of 2d array. That will change the whole process of iterating also.
I am very new to javascript. I don't know any of the syntax for javascript. Please help me doing that.
declare a map object
var map = new Map(); // or var map = {};
inserting a new item
map.set(key, value);
in your case you can use like map.set(1,['a','b','c','d']);
retrieving a item
map.get(key); // will return value
for more detailed uses see this https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

How to work with variables dynamically in javascript?

I need to work with variables dynamically, and get them dynamically too. The first thing I need to know is:
How to save a variable reference(NOT its value) in a collection?
Example:
var divA = "<div>my div A</div>";
var divB = "<div>my div B</div>";
var divC = "<div>my div C</div>";
Then, save in a collection:
var mySet = new Set();
function returnDivA(){
return divA;
}
function returnDivB(){
return divB;
}
function returnDivC(){
return divC;
}
mySet.add(returnDivA());//I would like save the varible ref in a collection.
mySet.add(returnDivB());
mySet.add(returnDivC());
I want the Set collection to save the variables(NOT its values), it means:
var mySet = new Set(divA, divB, divC);
Then, with that, my intent is to do something like that:
var totalOfDivs;
for(var i = 0; i < mySet.size; i++){
totalOfDivs += mySet[i];
}
$("#anotherDIV_to_show_all_divs").html(totalOfDivs);//Then, here, I want to show all divs in the screen.
I would like suggestions, please!
It solved my problem to put variable dynamically in html using this in a for loop:
$("#anotherDIV_to_show_all_divs").append(mySet[i]);
About saving javascript variable reference in a Collection, I understand that I can't do that, because of the answer of the adeneo in comment:
"There is no "reference", all variables are pass-by-value in javascript..."
Read the documentation about set.
enter link description here
I guess you have to loop your set like this.
var totalOfDivs= "";
for (let item of mySet.values()) {
totalOfDivs+= item;
//console.log(item);
}
$("#anotherDIV_to_show_all_divs").html(totalOfDivs);

Get all items in NotesXSPDocument

In my Notes Database, I perform an audit when the document is saved. Pretty easy in LotusScript. I grab the original document (oDoc) from the server, then in the document I modified (mDoc), I do a Forall loop that gets the names of each item; forall item in mDoc.items. Grab the same item from oDoc, execute a function with the new item as an argument that will run down a case statement that will see if its a field we care about. if so, I update a set of list values in the document with "When", "Who", "What field", and the "New Value".
I'm doing this in a server side script. In trying this, I discovered a couple of interesting things;
currentDocument is the NotesXSPDocument that contains everything that was just changed.
currentDocument.getDocument() contains the pre-change values. It also returns a NotesDocument which has the "items" field that I can run through.
Thing is, I need something similar in the NotesXSPDocument. Is there a way in an iterative loop to grab the names and values of all items from there?
Here's the broken code. (Currently it's walking through the NotesDocument items, but those are the old values. I'd rather walk down the XSP document items)
function FInvoice_beginAudit() {
var original_doc:NotesDocument = currentDocument.getDocument();
var oItem:NotesItem;
var oItems:java.util.Vector = original_doc.getItems();
var iterator = oItems.iterator();
while (iterator.hasNext()) {
var oItem:NotesItem = iterator.next();
item = currentDocument.getItemValue(oItem.getName());
if (oItem == undefined) {
var MasterItem = ScreenAudit(doc,item,True)
if (MasterItem) { return true }
} else {
if (item.getValueString() != oItem.getValueString()) {
var MasterItem = ScreenAudit(doc,Item,True);
if (MasterItem) { return true }
}
}
}
}
You can get both versions of a document after submit - the original and the one with changed/new values:
original: var original_doc:NotesDocument = currentDocument.getDocument();
changed: var changed_doc:NotesDocument = currentDocument.getDocument(true);
This way you can compare the items for changes.
But, there is a pitfall: after assigning "changed_doc" to currentDocument.getDocument(true) the "original_doc" has the changed values too because both variables point to the same document. That's why we have to copy all items from currentDocument.getDocument() to a new temporary document first and only after get the changed values with currentDocument.getDocument(true). As an alternative you could read the original document from server like you do in LotusScript.
This is a code for detecting changed items as a starting point:
var original_doc:NotesDocument = database.createDocument();
currentDocument.getDocument().copyAllItems(original_doc, true);
var changed_doc:NotesDocument = currentDocument.getDocument(true);
var oItems:java.util.Vector = original_doc.getItems();
var iterator = oItems.iterator();
while (iterator.hasNext()) {
var oItem:NotesItem = iterator.next();
var itemName = oItem.getName();
var cItem:NotesItem = changed_doc.getFirstItem(itemName);
if (cItem.getText() !== oItem.getText()) {
print("changed: " + itemName);
}
oItem.recycle();
cItem.recycle();
}
original_doc.remove(true);
original_doc.recycle();

Categories