I'm encountering an implementation problem I need some help with:
I am building a Google Docs integration that involves programmatically creating a table and then mapping through an array of records to add the data of those records to the table cells. I'm able to create a blank table and locate the start index of each cell to insert the data into, but when I try to use the insertText request from the docs and place the text in a specific cell I get the following error:
"Invalid request[1].insertText: The insertion index must be inside the
bounds of an existing paragraph. You can still create new paragraph by
inserting new lines."
I've tried the following
Simply inserting my text and hoping that each insertText request places text in a new cell
Adding '\n' at the start index of the cells
Creating the table with tableRows already defined (this error
out as an invalid request format)
Creating cells one-by-one and inserting text after each appended 1x1 column or row (eventually you create a row that duplicated the row above it with multiple columns and all text would just be in the first cell)
Inserting Column breaks after the first cells text in hopes it would shift the
paragraph over to the new cell
Here's the last implementation I tried:
(For context I aim to filter through an items array, create a table for each item, and then for every subitem in that item object to have a table row where relevant data will go under Header 1, 2 and 3, but for now I'd be happy just to get the tables and headers in the right places)
var requests = []
await Promise.all(
items.map(async (item) => {
let subitems = []
subitems = item.subitems.filter((subitem) => subitem.selected)
//Create table api call
await docs.documents
.batchUpdate({
documentId: newDoc.data.documentId,
resource: {
requests: [
{
insertTable: {
columns: 3,
rows: item.subitems.length + 1,
endOfSegmentLocation: { segmentId: '' },
},
},
],
},
})
.then((res) => res.data)
//Api call for cell data
var docData = await docs.documents
.get({
documentId: newDoc.data.documentId,
})
.then((res) => res.data)
requests.push(
{
insertText: {
text: 'Header 1',
location: {
index:
docData.body.content[2].table.tableRows[0].tableCells[0]
.startIndex,
},
},
},
{
insertText: {
text: 'Header 2',
location: {
index:
docData.body.content[2].table.tableRows[0].tableCells[1]
.startIndex,
},
},
},
{
insertText: {
text: 'Header 3',
location: {
index:
docData.body.content[2].table.tableRows[0].tableCells[2]
.startIndex,
},
},
}
)
})
)
//Insert Text API call
var myDoc = await docs.documents
.batchUpdate({
documentId: newDoc.data.documentId,
resource: {
requests,
},
})
.then((res) => res.data)
return myDoc
}
If you need any more info let me know. Thanks in advance.
Related
I have a JavaScript code that scrapes data in a dl Description List.
There are possible 7 dt values with respective dd values.
Only those of the 7 dt values and their dd values are shown on the website that have at least 1 dd value - thus, it can be 1 dt incl. dd is scraped or in another webpage 7
OK, I have a working Javascript code, that does the job!
const columns = [
{ text: 'Website', name: 'Website' },
{ text: 'Phone', name: 'Phone' },
{ text: 'Industry', name: 'Industry' },
{ text: 'Company size', name: 'Companysize' },
{ text: 'Headquarters', name: 'Headquarters' },
{ text: 'Founded', name: 'Founded' },
{ text: 'Specialties', name: 'Specialties' },
{ text: 'Employees', name: 'Employees' }
]
const result = [];
const elements = document.querySelectorAll('dl dt');
elements.forEach((element) => {
const regex = new RegExp(element.innerText, 'i');
const findColumn = columns.find((column) => regex.test(column.text));
if (!findColumn) return;
const columnValue = element.nextElementSibling.innerText;
result.push({ [findColumn.name]: columnValue });
});
Problem
I want to save the scraping results in an MS Excel table that has 7 columns
BUT --> The result of the scraping can have1 up to 7 columns
Because of that, I can't simply append the results, row by row - I have to do it manually. Copying the right value in the right column for it.
I would need a code that can do the following:
The values of the 7 dt elements are the header of the 7 columns
The code always results in 7 values
If the ddis a real value and accordingly scraped by the code above, then it is put in the correct column
If there is no dt element, then the string "n/a" should be put under the respective column.
This way, the results are stored in a consistent Excel table with always the correct values in the correct column.
I cannot find any specific info or material or sample code to write JavaScript code to solve this task! I think, a JavaScript expert is needed to write that code.
Thank you for helping me out to understand JavaScript better and to learn how to write JS code.
P.S.: The website scraping from: LinkedIn companies
I'm using select2 load remote data way to render results (50 at a time) from an api. The response of the api might have duplicate values in any page response.
I have tried formatting response but unfortunately the method is having access only to the current page data.
Below is my code,
jQuery('#items').select2({
minimumInputLength : 2,
placeholder : '-- Select Items --',
ajax : {
url : '/api/v1/items',
quietMillis : 200,
dataType : 'json',
data : function (term, page) {
return {
term : term,
page : page,
page_limit : 50
};
},
results : function(data, page) {
//Here I'm getting only current page data. How can i get previous page data to check for duplicate values.
}
}
});
So, how can I filter the response and eliminate duplicate values by checking against the data fetched so far.
Any help would be appreciated.
It would be better if you post an example of your code. Let's say you have some data with duplicated entries:
var rawData = [
{
id: 'AL',
name: 'Alaska'
},
{
id: 'GE',
name: 'Georgia'
},
{
id: 'WY',
name: 'Wyoming'
},
{
id: 'GE',
name: 'Georgia'
}
];
function clearDuplicates(data) {
var temp = {};
for (var i = 0; i < data.length; i++) {
temp[data[i]['id']] = data[i];
}
return Object.values(temp);
}
var clearData = clearDuplicates(rawData);
console.log(clearData);
See output: duplicated entry 'Georgia' is now in one record. There can be a lot of ways to eliminate duplicates. This is just one simple example.
UPDATE:
If you use pagination (infinite scroll) in Select2, every page request is sent separately and you have to process result data and eliminate duplicates manually. it can be done by processResults parameter. (See example)
In that case, easiest way would be:
Handle every page request in processResults
Store all results in a global variable
Eliminate duplicates as described in the example above
Return desired result
Return:
return {
results: <YOUR_FILTERED_DATA>,
pagination: {
//paginatioin params
}
}
I have used exceljs module in nodejs for exporting json data to excel. It's working fine, but the names of headers/columns have to be predefined before adding rows i.e., columns are fixed. After addition of rows, I can't add columns dynamically.
I have tried a number of modules available through npm but all of them have the same features.
So, is there any way or module that, at the time of manipulation of json data, can create a new column and add the required row.
If someone is still looking into this problem then I have a decent solution.
Instead of creating columns, you can create a table as follows in the worksheet.
worksheet.addTable({
name: "MyTable",
ref: "A1",
headerRow: true,
totalsRow: false,
style: {
theme: null,
showRowStripes: true,
showColumnStripes: true,
},
columns: [
{ name: "EmployeeID" },
{ name: "First Name" },
],
rows: [/* Enter initial rows if you want to add*/],
});
After adding a table to the column A1 of your worksheet you can add new columns dynamically
const table = worksheet.getTable("MyTable");
table.addColumn({
name: "Column name",
});
table.commit();
I tried directly pushing the new columns to the worksheet.columns but it is not working. I did a workaround and working well for me.
Note: You need to make the track of already added columns in the worksheet to get the next empty columns by column index.
Here is an example:
let workbook = new excel.Workbook(); //creating workbook
let worksheet = workbook.addWorksheet('Records'); //creating worksheet
const columns = [];
columns.push({header: 'Id', key: '_id', width: 30});
columns.push({header: 'Name', key: 'name', width: 30});
//Set Headers to WorkSheet Header
worksheet.columns = columns;
//Now insert some records if you want
worksheet.addRow({_id: "1", name: "Mitchell Starc"});
worksheet.addRow({_id: "2", name: "Ab de Villiers"});
//Update or add dynamic columns
//Get the empty columns from worksheet. You can get the empty columns number by using `columns` array length
//For this you have to track all inserted columns in worksheet
//This will return the next empty columns
let newColumn = worksheet.getColumn(columns.length + 1);
//Set new key header and all other required properties
newColumn.key = "profession";
newColumn.header = "Profession";
newColumn.width = 30;
//Add the new column to `columns` to track the added headers
columns.push(newColumn);
//Now you can insert rows with new columns
worksheet.addRow({_id: "3", name: "MS Dhoni", profession: "Cricket"});
workbook.xlsx.writeFile("records.xlsx")
.then(function () {
console.log("file saved!");
});
Now not sure if this worked 2 years ago but this worked for me
var columns=[]
x="data1"
y="data2"
Columns.push({ header: x, key: x })
Columns.push({ header: y, key: y})
worksheet.columns = Columns
You must use a separate variable to dynamically create the array of structs for it to work. if you use worksheet.columns=[] and worksheet.columns.push(..) it will fail.
So I'm trying to insert an array of records of length to Azure Table. I'm on New Azure portal, and all the help I found was for old one.
New Azure Portal's Script page looks like
I've tried to override the insert method as following:
var table = require('azure-mobile-apps').table();
table.insert(function (context) {
all_answers = context.item.answers;
console.log(all_answers[0]);
return context.execute();
});
Log shows the following object:
{ id: '',
userid: '0029C048-B8A0-42AE-B8F8-2B9402D69EEF',
createdate: '2016-01-30 00:40:18',
questionid: 1,
choiceid: 0
}
How can I insert all records of array in Table?
Anticipated Thanks
I'm thinking that I am overlooking something simple - I am so close to making this work. :)
I have a grid that needs to be updated with server information.
Here is the way that it should work:
A user selects an item
Make a JsonRest query with the item ID selected
Update the grid - showing notes relating to item selected
Here is how the grid is setup:
function noteTabSetup() {
var store = JsonRest({target:"//localhost/program/notes", idAttribute:"id"});
var structure = [{ field: 'id', name: 'Id', width: '5em' },
{ field: 'name', name: 'Name', width: '12%' },
{ field: 'description', name: 'Description' }];
var noteGrid = new Grid({
id: 'noteGrid',
pageSize: 20,
store: store,
cacheClass: Cache,
structure: structure,
filterServerMode: true,
selectRowTriggerOnCell: true,
bodyLoadingInfo: "Loading notes ...",
bodyEmptyInfo: "No notes found",
modules: [SingleSort, VirtualVScroller, moveColumn,
selectColumn, dndColumn, selectRow, Filter]}, noteTab);
noteGrid.startup();
When an item is selected, the selected item ID is passed to:
function noteLoad(itemId) {
console.log("In NoteLoad");
var grid = registry.byId("noteGrid");
if (!itemIds || 0 === itemIds.length) { console.log("no ItemId chosen"); }
else {
console.log("In NoteLoad with an itemId");
grid.model.clearCache();
// Error on second run
grid.store.query({ find: "ByItem", item: itemId }).then(function(result) {
grid.setStore(new ItemFileReadStore({data: {items : result}}));
});
grid.body.refresh();
console.log("model: " + grid.rowCount());
};
};
On the first item selected, everything works well - the query fires, and the grid is updated with notes related to the selected item.
On the second item selected, I receive this error from firebug:
TypeError: grid.store.query is not a function
grid.store.query({ find: "ByItem", item: itemIds }).then(function(result) {
-----------------------------------^
Any ideas?! Thank you in advance.
Chris
Thank you for the reply - that makes sense that store was being replaced by ItemFileReadStore. If possible, I would like to use JsonRest directly to update the grid.
I've tried a handful of variations based off of your comment, without luck:
Query fires and result is returned. Grid is not updated:
grid.model.clearCache();
grid.store.query({ find: "ByItem", item: itemIds }).then(function(results){
console.log('notes: ' + results[0].name);
});
grid.body.refresh();
Error: grid.store.fetch is not a function:
grid.store.fetch({ query: { find: "ByItem", item: itemIds }});
Syntax error in Dojo.js (line 15):
grid.store.query({ find: "ByItem", item: itemIds }).then(function(result) {
grid.setStore(new JsonRest({data: {items : result}}));
});
I've done a lot of searches and can't find a good example where the grid is being updated from a JsonRest object. Thank you.
Because the code itself replaces the store the first time.
grid.store.query({ find: "ByItem", item: itemId }).then(function(result) {
grid.setStore(new ItemFileReadStore({data: {items : result}}));
});
Here, the grid's store is initially JsonRest store, which after the query method is run, is replaced by the new ItemFileReadStore object. The mistake here is "query" is not a method of ItemFileReadStore, but the parameter passed to the "fetch" method. Check out some examples from dojo documentation on this.
On the other hand, JsonRest store has the method "query". Hence the contradiction. Change your code accordingly if you want ItemFileReadStore.
eg:-
store.fetch( { query: { name: 'Ice cream' },
onItem: function(item) {
console.log( store.getValue( item, 'name' ) );
console.log( 'cost: ', store.getValue( item, 'cost' ) );
}
});