Find available range in Excel in JS API - excel

I have a requirement in my add in where I need to insert a table in Excel. But I need to know if the available cell range is empty for my table to insert there. So I have to check that if my cursor is at A1, do we have available space from A1 to A15 and there is no existing data there.
I tried getRangeByIndexes() function but this just gives a range. I can't find a function that returns a boolean for my requirement.

Excel will always have "space" to insert data/table. I guess you want to make sure the cells are in fact empty before inserting table? If so, you can get getSelectedRange() API and use getOffsetRange() to select both the selected range (load just the address and values) and the range associated table dimension (load just values). You can then check to make sure values are empty before inserting.
Another way could be to check worksheet.getUsedRange() to ensure the used range is just A1 (empty worksheet). This only works if you are ensuring that the whole worksheet is empty (not just the table's address).

There are a number of ways of doing this. I think the best one is to use a combination of getSelectedRange, getAbsoluteResizedRange, and getUsedRangeOrNullObject
await Excel.run(async (context) => {
let numRows = 10;
let numColumns = 3;
let range = context.workbook.getSelectedRange().getCell(0, 0).getAbsoluteResizedRange(numRows, numColumns);
let usedRange = range.getUsedRangeOrNullObject(true /*valuesOnly*/);
await context.sync();
if (usedRange.isNullObject) {
console.log("The range is empty");
} else {
console.log("Sorry, it's already taken")
}
});
You can try this snippet live in literally five clicks in the new Script Lab (https://aka.ms/getscriptlab). Simply install the Script Lab add-in (free), then choose "Import" in the navigation menu, and use the following GIST URL: https://gist.github.com/Zlatkovsky/4835778375bb5f5b9d49bff4f5d522f0. See more info about importing snippets to Script Lab.
The objects returned by *OrNullObject-sufficed methods are a bit unusual. If you've not run into them before, I recommend you read about it in our docs. I also go into great detail about it in my book, "Building Office Add-ins using Office.js" (with all profits to charity), in a chapter entitled "9. Checking if an object exists".

Related

Creating a Unique ID for each record on Form Submission

I am new to Google Apps Script and have just begun to understand its working. A team member wrote out a simple simple script for some work i was doing. The script, in essence, triggered when any of a permitted set of users (could vary) submits inputs to a 'Form Responses 1' spreadsheet via a Google Form.
Basically, I have a form that users complete and then submit. Upon submission, the script checks for the active row, The code adds 1 to the number of the cell W2 (which is a 'do not edit' cell, and replaces W2 with the new number, then checks if the Unique ID field on the Active Row is null and then replaces it with a concatenated ID thats alphanumeric. ie, it prefixes a set alphabetical prefix and takes the numerical input from the cell W2 on the same form to create a new Unique ID.
The script was working perfectly until the team member left and I removed her access from the Google sheets with no change to the script at all. I've been scrambling trying to figure out what happened after that, because since access was removed, when I haven't made any changes to my code. I have searched many different places and cannot seem to find what is wrong.
If i post it on a new google sheet, it's working fine .. but not on this sheet which already has around 900 critical entries.
Any guidance is welcome. the Script is as below. HELP!
//Logger.log(SpreadsheetApp.getActiveSpreadsheet().getUrl());
//Logger.log(SpreadsheetApp.getActive().getUrl());
// Get the active sheet
var sheet = SpreadsheetApp.getActiveSheet();
// Get the active row
var row = sheet.getActiveCell().getRowIndex();
// Get the next ID value. NOTE: This cell should be set to the last record counter value
var id = sheet.getRange("X2").getValue()+1;
Logger.log("HKG0"+id);
// Check if ID column is empty
if (sheet.getRange(row, 1).getValue() == "") {
// Set new ID value
sheet.getRange(2, 24).setValue(id);
sheet.getRange(row, 1).setValue("HKG0"+id);
}
}
If your code is running off of a form submit trigger then this should work for you.
function formsubit(e) {
Logger.log(JSON.stringify(e));
var sheet = e.range.getSheet();
var id = sheet.getRange("X2").getValue() + 1;
if (sheet.getRange(e.range.rowStart, 1).getValue() == "") {
sheet.getRange(2, 24).setValue(id);
sheet.getRange(e.range.rowStart, 1).setValue("HKG0" + id);
}
}
The Logger.log will help you to learn more about the event object. You can learn more about event objects here
If you're looking for a unique id for each submission try: const id = new Date(e.values[0]).valueOf(); it's the number of milliseconds since Jan 1, 1970

how to add table within another table cell using only office api from the document editor plugin

We are trying to add table within another table cell using only office api from the document editor plugin. We tried to find out various methods like using Range, Run Command, ParagraphAddDrawing, AddElement etc. to do it , but are unable to find a way to achieve it.
Please advice us an proper way to achieve this using API as early as possible...
Regards
You need to get cell and use method Push() on it.
Example:
var oDocument = Api.GetDocument(); // getting document object
var oParagraph, oTable, oCell; // init variables
oTable = Api.CreateTable(3, 3); // creating new table object
oCell = oTable.GetRow(0).GetCell(0); //getting first cell in first row
oDocument.Push(oTable); // Push new table to document
oTable_two = Api.CreateTable(3, 3); // creating second table object
oParagraph = oCell.GetContent().Push(oTable_two); // pushing new table to first table

Excel Add-in Row Index and Values are returned as undefined

I am trying to remove some rows in a table via Excel add-in. The code that I am using is below:
var table = ctx.workbook.tables.getItem('TableName');
if (Office.context.requirements.isSetSupported('ExcelApi', 1.2) === true) {
table.clearFilters();
}
var tableRows = table.rows.load('items');
ctx.sync().then(function () {
for (var i = (tableRows.count - 1); i >= 0; i -= 1) {
var row = tableRows.getItemAt(tableRows.items[i].index);
row.delete();
}
});
This works fine in Excel online including Internet Explorer 11. Also it works with version 1601 (Build 6741.2088) and later. However, it doesn't work with version 1509 (Build 4266.1001). In this version I get the values and indexes of row items as undefined. How can I resolve this issue?
I am not sure what difference the build numbers would make -- but I will say that the TableRow API is the one API that is brittle (and we're looking into how to fix it). Essentially, when you do a getItemAt, you're creating a reference based on the point-in-time index, and this index does not get adjusted when new rows are added or deleted.
In other words, for deletion/insertion, I would treat it like you need to invalidate the table rows collection, and/or would use Range objects instead. Again, note that this statement applies only to the TableRow/TableRowCollection objects -- other collections, like the worksheet collection, adjust correctly.

How do you determine which row was selected in a Infragistics WebHierarchicalDataGrid when you have a Master Detail table configuration

I have a master table and two child detail tables under the master. When the user selects one of the detail tables the RowSelection event fires. I need to determine which table was selected. If the users selectes the second detail table then I need to obtain the data from a specific field. What code can be put in place to make this determination. Here is the code I have so far to grab the data, I just need to build the IF statment around this code.
String UploadIndex;
if (e.CurrentSelectedRows.Count > 0)
{
GridRecord oRow = e.CurrentSelectedRows[0];
UploadIndex = oRow.Items[0].Value.ToString();
}
Tried this but got controlmain is inaccessible due to its protection level.
ContainerGrid oRowIsland = WebHierarchicalDataGrid1.GridView.Rows[e.CurrentSelectedRows[0].Index].RowIslands[0];
if (oRow.Owner.ControlMain.ID == '2')
{
UploadIndex = oRow.Items[0].Value.ToString();
}
Use ContainerGridRecord type instead of GridRecord when declaring oRow, this way you will have access to oRow.Owner.ControlMain which is the grid that holds the row. In debug determine ID of the grid you're interested in and then you can do
If (oRow.Owner.ControlMain.ID == '...ID of second grid') {
// profit
}
Or use some other easily identifiable property of ControlMain grid that in your case assocciate with the second details.

YUI Column Selection

I'm having issues using YUI's DataTable Column Selection Functionality. I've tried,
myEndColDataTable.subscribe("theadCellClickEvent", myEndColDataTable.onEventSelectColumn);
and
myEndColDataTable.subscribe("cellClickEvent", function (oArgs) {
this.selectColumn(this.getColumn(oArgs.target));
});
The issue is, I have an initial column selected programmatically. I can highlight the other column, but it doesn't remove the selection from the initially-selected column.
You are correct - there is no quick clean solution.
YUI DataTable currently (as of 2.8) lacks an unselectAllColmns method to match unselectAllRows (which is called by onEventSelectRow).
It is also worth noting that onEventSelectColumn selects the column header, so unselectAllCells will not work.
You could implement your own unselectAllColumns() function like this:
function unselectAllColumns (dataTable) {
var i, oColumn, oColumnSet = dataTable.getColumnSet();
for (i=0; i<oColumnSet.keys.length; i++) {
oColumn = oColumnSet.keys[i];
if (oColumn.selected) {
dataTable.unselectColumn(oColumn);
}
}
}
This will be marginally more efficient than using getSelectedColumns() because you will not need to build an intermediate array of only selected columns (looking at the source getSelectedColumns calls getColumnSet and walks the array just as above).
I guess I can do this, but its not elegant. There has to be a better way.
myEndColDataTable.subscribe("cellClickEvent", function (oArgs) {
var colUnSelect = myEndColDataTable.getSelectedColumns();
myEndColDataTable.unselectColumn(colUnSelect[0]);
myEndColDataTable.selectColumn(myEndColDataTable.getColumn(oArgs.target));
});

Resources