Create a XLS file dynamically with XLSX in Angular - xlsx

I'm creating a pickList where there's a list of attributes that the user can choose to create its own personal report. But I'm having quite some trouble on creating this XLS, because of two things.
First my XLSX.utils.json_to_sheet is ignoring blank fields (""), and I can't have that because it will desorganize the whole report.
Second: because its a dynamic xls, I can't know how many columns there will be created...
Here's what I've done so far, regarding the xls creation part:
exportTable() {
this.createObjectWithColumnsSelected(); //ignore this, i'm only creating a reference object based on the user columns choices
this.manipulateExportableData(); //manipulating the whole table data, to be formated accordly the reference object
const worksheet = XLSX.utils.json_to_sheet(this.customersTable);
this.changeHeaderWorksheet(worksheet);
}
converte(): string[] {
const alph = "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ";
return alph.split('');
}
changeHeaderWorksheet(worksheet: WorkSheet): void {
const alphabet = this.converte();
for (let i = 0; i < this.cols.length; i++) {
if (i >= 26){
console.log(this.cols[i].header);
worksheet[`A${alphabet[i]}1`] = this.cols[i].header;// I think this is quite wrong
}else{
console.log(this.cols[i].header);
worksheet[`${alphabet[i]}1`] = this.cols[i].header; //I think this is quite wrong
}
}
}

Related

This script wont select elements/layers which thier names are between angle-brackets "<>"

Whenever I open a PDF-file in Illustrator for edithing, there are a lot of ungrouped and uncategorized Elemetns in it.
So I tried to select multiple elements with a spicific name with the below Script, but since the name of the elements are between Angle-brackets "<someName>" script wont select them:
function selectPageItemsByName(items, name) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.name === name) {
item.selected = true;
}
}
}
function main() {
var document = app.activeDocument;
var name = '<someFile>';
document.selection = null;
selectPageItemsByName(document.pageItems, name);
}
main();
Femkeblanko from Adobe Community says: Items with angle brackets in their label (unless user-created) are unnamed. They correspond to an empty string, i.e. "".
If I remove the Brackets from the name of the Elemetns, the script works but I have a lot of Elements and it needs time.
So, isn't there a way to salve it?
this is a pretty creative way:
// Select->Objects->Clipping Mask
app.executeMenuCommand("Clipping Masks menu item");
// Edit->Clear
app.executeMenuCommand("clear");
but it isn't really documented very well
some links for future reference:
Where is the perfect reference of adobe illustrator script?
https://ai-scripting.docsforadobe.dev/index.html
https://ten-artai.com/illustrator-ccver-22-menu-commands-list/
https://github.com/ten-A/AiMenuObject

Google Apps Script - Optimizing File Creation/Modification

I reviewed the following documentation from Google on how to optimize existing Google scripts here:
https://developers.google.com/apps-script/guides/support/best-practices
In particular, the 'Use batch-operation' section seems more appropriate for my use case, where the optimal strategy is to 'batch' all the reading into one operation, and then writing in separate operation; not to cycle between read-and-write calls.
Here is an example of inefficient code, as given by the url above:
// DO NOT USE THIS CODE. It is an example of SLOW, INEFFICIENT code.
// FOR DEMONSTRATION ONLY
var cell = sheet.getRange('a1');
for (var y = 0; y < 100; y++) {
xcoord = xmin;
for (var x = 0; x < 100; x++) {
var c = getColorFromCoordinates(xcoord, ycoord);
cell.offset(y, x).setBackgroundColor(c);
xcoord += xincrement;
}
ycoord -= yincrement;
SpreadsheetApp.flush();
}
Here is an example of efficient and improved code:
// OKAY TO USE THIS EXAMPLE or code based on it.
var cell = sheet.getRange('a1');
var colors = new Array(100);
for (var y = 0; y < 100; y++) {
xcoord = xmin;
colors[y] = new Array(100);
for (var x = 0; x < 100; x++) {
colors[y][x] = getColorFromCoordinates(xcoord, ycoord);
xcoord += xincrement;
}
ycoord -= yincrement;
}
sheet.getRange(1, 1, 100, 100).setBackgroundColors(colors);
Now, for my particular use case:
Instead of storing values in an array, then writing/modifying them as a separate operation from reading them into an array, I want to create multiple Google documents that replaced placeholders within each document.
For context:
I'm writing a script that reads a spreadsheet of students with files to modify for each student, which is later sent as a mail merge. For example, there are 3 master files. Each student will have a copy of the 3 master files, which is used to .replaceText placeholder fields.
Here are my relevant snippets of code below:
function filesAndEmails() {
// Import the Spreadsheet application library.
const UI = SpreadsheetApp.getUi();
// Try calling the functions below; catch any error messages that occur to display as alert window.
try {
// Prompt and record user's email draft template.
// var emailLinkID = connectDocument(
// UI,
// title="Step 1/2: Google Document (Email Draft) Connection",
// dialog=`What email draft template are you referring to?
// This file should contain the subject line, name and body.
// Copy and paste the direct URL link to the Google Docs:`,
// isFile=true
// );
// TEST
var emailLinkID = "REMOVED FOR PRIVACY";
if (emailLinkID != -1) {
// Prompt and record user's desired folder location to store generated files.
// var fldrID = connectDocument(
// UI,
// title="Step 2/2: Google Folder (Storage) Connection",
// dialog=`Which folder would you like all the generated file(s) to be stored at?
// Copy and paste the direct URL link to the Google folder:`,
// isFile=false
// );
// TEST
var fldrID = DriveApp.getFolderById("REMOVED FOR PRIVACY");
// Retrieve data set from database.
var sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_1);
// Range of data must include header row for proper key mapping.
var arrayOfStudentObj = objectify(sheet.getRange(3, 1, sheet.getLastRow()-2, 11).getValues());
// Establish array of attachment objects for filename and file url.
var arrayOfAttachObj = getAttachments();
// Opportunities for optimization begins here.
// Iterate through array of student Objects to extract each mapped key values for Google document insertion and emailing.
// Time Complexity: O(n^3)
arrayOfStudentObj.forEach(function(student) {
if (student[EMAIL_SENT_COL] == '') {
try {
arrayOfAttachObj.forEach(function(attachment) {
// All generated files will contain this filename format, followed by the attachment filename/description.
var filename = `${student[RYE_ID_COL]} ${student[FNAME_COL]} ${student[LNAME_COL]} ${attachment[ATTACH_FILENAME_COL]}`;
// Create a copy of the current iteration/file for the given student.
var file = DocumentApp.openById(DriveApp.getFileById(getID(attachment[ATTACH_FILEURL_COL], isFile=false)).makeCopy(filename, fldrID).getId())
// Replace and save all custom fields for the given student at this current iteration/file.
replaceCustomFields(file, student);
});
} catch(e) {
}
}
});
UI.alert("Script successfully completed!");
};
} catch(e) {
UI.alert("Error Detected", e.message + "\n\nContact a developer for help.", UI.ButtonSet.OK);
};
}
/**
* Replaces all fields specified by 'attributesArray' given student's file.
* #param {Object} file A single file object used to replace all custom fields with.
* #param {Object} student A single student object that contains all custom field attributes.
*/
function replaceCustomFields(file, student) {
// Iterate through each student's attribute (first name, last name, etc.) to change each field.
attributesArray.forEach(function(attribute) {
file.getBody()
.replaceText(attribute, student[attribute]);
});
// Must save and close file to finalize changes prior to moving onto next student object.
file.saveAndClose();
}
/**
* Processes the attachments sheet for filename and file ID.
* #return {Array} An array of attachment file objects.
*/
function getAttachments() {
var files = SpreadsheetApp.getActive().getSheetByName(SHEET_2);
return objectify(files.getRange(1, 1, files.getLastRow(), 2).getValues());
}
/**
* Creates student objects to contain the object attributes for each student based on
* the header row.
* #param {Array} array A 2D heterogeneous array includes the header row for attribute key mapping.
* #return {Array} An array of student objects.
*/
function objectify(array) {
var keys = array.shift();
var objects = array.map(function (values) {
return keys.reduce(function (o, k, i) {
o[k] = values[i];
return o;
}, {});
});
return objects;
}
To summarize my code, I read the Google spreadsheet of students as an array of objects, so each student has attributes like their first name, last name, email, etc. I have done the same for the file attachments that would be included for each student. Currently, the forEach loop iterates through each student object, creates copies of the master file(s), replaces placeholder text in each file, then saves them in a folder. Eventually, I will be sending these file(s) to each student with the MailApp. However, due to the repetitive external calls via creating file copies for each student, the execution time is understandably very slow...
TLDR
Is it still possible to optimize my code using "batch operations" when it is necessary for my use case to have multiple DriveApp calls to create said copies of the files for modification purposes? As opposed to reading raw values into an array and modifying them at a later operation, I don't think I could simply just store document objects into an array, then modify them at a later stage. Thoughts?
You could use batchUpdate of Google Docs API.
See Tanaike's answer just to have an idea on how the request object looks like.
All you need to do in your Apps Script now is build the object for multiple files.
Note:
You can also further optimize your code by updating:
var arrayOfStudentObj = objectify(sheet.getRange(3, 1, sheet.getLastRow()-2, 11).getValues();
into:
// what column your email confirmation is which is 0-index
// assuming column K contains the email confirmation (11 - 1 = 10)
var emailSentColumn = 10;
// filter data, don't include rows with blank values in column K
var arrayOfStudentObj = objectify(sheet.getRange(3, 1, sheet.getLastRow()-2, 11).getValues().filter(row=>row[emailSentColumn]));
This way, you can remove your condition if (student[EMAIL_SENT_COL] == '') { below and lessen the number of loops.
Resource:
Google Docs Apps Script Quickstart
Google Docs REST API

Is there anyway to dynamically access an object from a Utility Class in EXTJS?

My code structure is as follows->
MyApp-> app -> model, view, controller, store, utils
I have the following utility class created for my validation errors:
Ext.define('MyApp.shared.utils.GlobalStrings', {
AmountLimitViolation: "Amount Limit Violated",
DurationLimitViolation: "Duration Limit Violated"
});
I am trying to get the strings dynamically in the following way, but they keep coming up undefined:
Ext.define('MyApp.controller.ViewController', {
extend: 'Ext.grid.Panel',
violationCheck: function (tradelimit, tradelimitViolations){
let me = this,
tradeViolationMessage = "";
if(tradelimit > 0){
for(i = 0; i < tradelimitViolations.length; i++){
violationString = tradelimitViolations[i] + "Violation";
tradeViolationMessage += GlobalStrings.violationString;
}
}
}
});
tradelimitViolations is a string that would contain something like: ("AmountLimit", "DurationLimit")
So is there any method I could use to get AmountLimitViolation and DurationLimitViolation dynamically without having to resort to using a long list of conditional statements? Because I'm just showing two of the many violation errors I have.
The problem is how you are "indexing" into GlobalStrings. The dot operator uses the text to the right as the key, but you have a variable holding your key.
Try this:
for(i = 0; i < tradelimitViolations.length; i++){
violationString = tradelimitViolations[i] + "Violation";
tradeViolationMessage += GlobalStrings[violationString];
}

Extracting Array inside a Property in Azure Stream Analytics

I have had no luck so far extracting certain values in a wide format out of a JSON string via a stream analytics job.
The JSON has the following format:
{"devicename":"demo","msgtime":"2018-04-13T11:00:00.0000000Z",
"payload":[{"Sensor":"one","Value":1.817,"Unit":"W"},
{"Sensor":"two","Value":0.481,"Unit":"W"},
{"Sensor":"three","Value":0.153,"Unit":"W"}]}}
I am trying to get it in the following format:
name one two three
demo 1.817 0.481 0.153
… … … …
I tried getting the values with "Cross APPLY GetPropertyValues(input)", but I can't get them in a wide format.
try code like below
SELECT
localInput.devicename,
udf.getValue('one', localInput.payload) as One,
udf.getValue('two', localInput.payload) as Two,
udf.getValue('three', localInput.payload) as Three
FROM localInput;
function main(identifier, arr) {
var result = null;
if (Object.prototype.toString.call(arr) == "[object Array]") {
for (i = 0; i < arr.length; i++) {
if (arr[i].type == identifier) {
result = arr[i].value;
}
}
}
return result;
}

Firebase Unity - Get all children into an array/generic list after GetValueAsync?

How can I get data back as an array or generic list from a Firebase database in Unity3D without knowing ahead of time what the name (key) of the children are?
I have been trying out the new Unity Firebase plugin, and I am having an issue figuring out how to get all the children in a specific location, and put the names (the key) and the values into arrays or generic lists so that I can work on the data locally. Forgive me for being so new to Firebase and probably using bad techniques to do this, and this plugin being so new its pretty hard for me to get much outside help, as there are not a lot of docs and tutorials out there on Firebase Unity.
In this particular case I am trying to create "instant messaging" like functionality, without the use of Firebase messaging, and just using regular Firebase database stuff instead. It might have been easier to use Firebase messaging, but mostly for the sake of learning and customization I want to do this on my own with just the Firebase database.
I insert data into the database like this:
public void SendMessage(string toUser, string msg)
{
Debug.Log(String.Format("Attempting to send message from {0} to {1}", username, toUser));
DatabaseReference reference = FirebaseDatabase.DefaultInstance.GetReference("Msgs");
string date = Magnet.M.GetCurrentDate();
// send data to the DB
reference.Child(toUser).Child(username).Child(date).SetValueAsync(msg);
// user receiving message / user sending message > VALUE = "hello dude|20170119111325"
UpdateUsers();
}
And then I try and get it back like this:
public string[] GetConversation(string userA, string userB)
{
// get a conversation between two users
string[] convo = new string[0];
FirebaseDatabase.DefaultInstance.GetReference("Msgs").GetValueAsync().ContinueWith(task =>
{
Debug.Log("Getting Conversation...");
if (task.IsFaulted || task.IsCanceled)
{
Debug.LogError("ERROR: Task error in GetConversation(): " + task.Exception);
}
else if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
string[] messagesA = new string[0], messagesB = new string[0];
if(snapshot.HasChild(userA))
{
// userA has a record of a conversation with other users
if(snapshot.Child(userA).HasChild(userB)) // userB has sent messages to userA before
{
Debug.Log("Found childA");
long count = snapshot.Child(userA).Child(userB).ChildrenCount;
messagesA = new string[count];
var kids = snapshot.Child(userA).Child(userB).Children;
Debug.Log(kids);
for (int i = 0; i < count; i++)
{
// this won't work, but is how I would like to access the data
messagesA[i] = kids[i].Value.ToString(); // AGAIN.... will not work...
}
}
}
if(snapshot.HasChild(userB))
{
if(snapshot.Child(userB).HasChild(userA)) // userA sent a message to userB before
{
Debug.Log("Found childB");
long count = snapshot.Child(userB).Child(userA).ChildrenCount;
messagesA = new string[count];
var kids = snapshot.Child(userB).Child(userA).Children;
Debug.Log(kids);
// messy incomplete testing code...
}
}
// HERE I WOULD ASSIGN ALL THE MESSAGES BETWEEN A AND B AS 'convo'...
}
Debug.Log("Done Getting Conversation.");
});
return convo;
}
But obviously this won't work, because DataSnapshot won't let me access it like an array or generic list using indices, and I can't figure out how to treat the data when I don't know the names (the keys) of all the children, and just want to get them out one by one in any order... and since they are named by the date/time they are entered into the DB, I won't know ahead of time what the childrens names (keys) are, and I can't just say "GetChild("20170101010101")" because that number is generated when its sent to the DB from any client.
FYI here is what the DB looks like:
Figured out the answer to your question. Here's my code snippet. Hope this would help!
void InitializeFirebase() {
FirebaseApp app = FirebaseApp.DefaultInstance;
app.SetEditorDatabaseUrl ("https://slol.firebaseio.com/");
FirebaseDatabase.DefaultInstance
.GetReference ("Products").OrderByChild ("category").EqualTo("livingroom")
.ValueChanged += (object sender2, ValueChangedEventArgs e2) => {
if (e2.DatabaseError != null) {
Debug.LogError (e2.DatabaseError.Message);
}
if (e2.Snapshot != null && e2.Snapshot.ChildrenCount > 0) {
foreach (var childSnapshot in e2.Snapshot.Children) {
var name = childSnapshot.Child ("name").Value.ToString ();
text.text = name.ToString();
Debug.Log(name.ToString());
//text.text = childSnapshot.ToString();
}
}
};
}
Firebase developer here.
Have you tried to use Value at the top level Snapshot? It should return to you an IDictionary where the values can also be lists or nested dictionaries. You will have to use some dynamic inspection to figure out what the values are.

Resources