I am trying to apply 'Fill' horizontal formatting to a cell but it is not working. I am using predefined Excel.HorizontalAlignment namespace to do so.
Host: Office 365, Excel
Code:
Excel.run(ctx => {
const cell = ctx.workbook.getSelectedRange().getCell(0, 0);
cell.format.fill.color = "FFFF00";
cell.format.horizontalAlignment = Excel.HorizontalAlignment.fill;
cell.format.font.size = 1;
return ctx.sync();
});
It throws with:
Unhandled promise rejection InvalidArgument: The argument is invalid or missing or has an incorrect format.
However, when I use the same code and set the alignment to 'Center' as such:
Excel.run(ctx => {
const cell = ctx.workbook.getSelectedRange().getCell(0, 0);
cell.format.fill.color = "FFFF00";
cell.format.horizontalAlignment = Excel.HorizontalAlignment.center;
cell.format.font.size = 1;
return ctx.sync();
});
Everything works just fine. What am I doing wrong?
Edit: documentation for reference: https://learn.microsoft.com/pl-pl/javascript/api/excel/excel.rangeformat?view=office-js#horizontalalignment
We reproed this locally, this should be a bug, we will fix it.
I withdraw this suggestion
cell.format.horizontalAlignment = xlFill;
or
cell.format.horizontalAlignment = Excel.HorizontalAlignment.xlFill;
I found this at horizontalAlignment doesn't work with xlFill
Related
I would like to do something like Grouping with a bottomRowCalc but having the visibility of the rows of data being optional. Currently I'm using getData('active') to add up the values and row.update() on the "sum" row with the values. But if I filter out the data rows, they wont appear in the getData('active'), so I'd have do a getData().forEach(row => {}) and manually check for another field flag I guess to see if it should be included in the sum.
It sure would be nice if I could continue to use getData('active') but set row.visibility(false) on rows I dont want to show, but still be in active ?
Is answering your own question a sin ?
Anyway, for posterity, in case anyone else wants to do this :
rowFormatter:function(row) {
let display = 'inline-block';
if (some_condition) display= 'none';
row.getElement().style.display = display;
return true;
}
rowFormatter: function(row){
var row_data= row.getData()
console.log('row_data is...',row_data);
if (row_data === 'yes'){
const children = row.getElement().childNodes;
children.forEach((child) => {
child.style.backgroundColor = 'red';
})
}
else (row_data === 'Upcomming')
{ let display = 'inline-block';
display= 'none';
row.getElement().style.display = display;
return true;
}
},
In this case you will miss s.r. with the row
I am trying to populate multiple ranges using a formula and then convert the range to values using paste as value. The Office add-in is being used on Sharepoint Excel for the web. The code usually works but once in a while I get a "Rich API: An internal error has occurred" error, due to which the formulas do not get replaced by values. After the first time, the error happens on every subsequent try it crashes with the "Rich API: Timeout" error. There are about 300 ranges of size approx 25x25.
Code:
async function loadValues() {
//This function is exectued to fill some ranges after data is retrived from server and pasted in a bacckend table
await Excel.run(async function main(context) {
context.workbook.application.calculationMode = "Manual";
let names = context.workbook.names
context.application.suspendScreenUpdatingUntilNextSync();
var rng = names.getItem("controlsToUse").getRange();
rng.load("values");
await context.sync();
context.application.suspendScreenUpdatingUntilNextSync();
// Controls to use contains the name of the ranges in which data has to be loaded and the ranges from which formula to load data has to be copied
var controlsToUse = rng.values;
for (i = 0; i < controlsToUse.length; i++) {
// str is the range in which data has to be pasted and str1 is the range from which formula has to be copied
var str = controlsToUse[i][0];
var str1 = controlsToUse[i][1];
var range1 = names.getItem(str).getRange();
range1.copyFrom(str1, Excel.RangeCopyType.formulas);
range1.untrack();
}
await context.sync();
context.workbook.application.calculate();
await context.sync();
context.application.suspendScreenUpdatingUntilNextSync();
for (i = 0; i < controlsToUse.length; i++) {
var str = controlsToUse[i][0];
var range1 = names.getItem(str).getRange();
range1.copyFrom(str, Excel.RangeCopyType.values);
range1.untrack();
}
await context.sync();
context.workbook.application.calculationMode = "Automatic";
await context.sync();
}).catch(errorHandler)
}
Can you comment out context.runtime.enableEvents = false; and check if it works?
I have just started with Office Addins and I'm experimenting with the functionalities. I have several VBA Userforms that I would want to replace with popups from the Office add-in.
I am using the following code to enter a string into a cell(nothing fancy, I know) but I would want to check if the cell if empty before passing the value. If it is, enter (arg.message).
the problem I have encountered:
with if (range.value == "") the value is being set in "A4" even if "A3" if empty;
with if (range.value == " ") the value is not being entered in any cells.
Can anyone give me an example of how to check if a cell is empty?
I know it seems trivial but I have only found examples of how to check with col and row numbers for conditional formatting. I am trying to test all these functionalities to be able to start moving stuff from VBA to OfficeJS.
Thanks,
Mike
function processMessage(arg) {
console.log(arg.message);
$('#user-name').text(arg.message);
dialog.close();
Excel.run(function (context) {
var sheet = context.workbook.worksheets.getItem("Sheet1");
var range = sheet.getRange("A3");
if (range.value == "") {
range.values = (arg.message);
range.format.autofitColumns();
return context.sync();
} else {
range.getOffsetRange(1, 0).values = (arg.message)
return context.sync();
}
}).catch(errorHandler);
}
PS: the whole code in case there is something wrong somewhere else
(function () {
"use strict";
// The initialize function must be run each time a new page is loaded.
Office.initialize = function (reason) {
$(document).ready(function () {
// Add a click event handler for the button.
$('#popup-button').click(opensesame);
$('#simple-button').click(function () {
Office.context.document.getSelectedDataAsync(Office.CoercionType.Text,
function (result) {
if (result.status === Office.AsyncResultStatus.Succeeded) {
$("#banner-text").text('The selected text is: "' + result.value + '"');
$("#banner").show(result.value);
console.log()
} else {
$("#banner-text").text('Error: ' + result.error.message);
$("#banner").show();
}
});
});
$("#banner-close").click(function () { $("#banner").hide(); });
$("#banner").hide();
});
}
let dialog = null;
function opensesame() {
Office.context.ui.displayDialogAsync(
'https://localhost:3000/popup.html',
{ height: 35, width: 25 },
function (result) {
dialog = result.value;
dialog.addEventHandler(Microsoft.Office.WebExtension.EventType.DialogMessageReceived, processMessage);
}
);
}
function processMessage(arg) {
console.log(arg.message);
$('#user-name').text(arg.message);
dialog.close();
Excel.run(function (context) {
var sheet = context.workbook.worksheets.getItem("Sheet1");
var range = sheet.getRange("A3");
if (range.value == "") {
range.values = (arg.message);
range.format.autofitColumns();
return context.sync();
} else {
range.getOffsetRange(1, 0).values = (arg.message)
return context.sync();
}
}).catch(errorHandler);
}
})();
The Range object has a values property, but not a value property. So range.value in your condition test is undefined which does not match an empty string; hence the else clause runs.
A couple of other things:
Your condition tries to read a property of the range object. You have to load the property and call context.sync before you can read the property.
The value of the range.values property is a two-dimensional array (although it may have a single value in it if the range is a single cell). It is not a string, so comparing it with an empty string will always be false.
If I understand your goal, I think you should be testing with whether range.values (after you load it and sync) has an empty string in it's only cell. For example, if (range.values[0][0] === ""). Even better from a performance standpoint is to load the range.valueTypes property (and sync) and then compare like this: if (range.valueTypes[0][0] === Excel.RangeValueType.empty).
I'm working on some code, mostly just playing around, with the Office-js API (v1.1), trying to do some things. I can take code examples and run them just fine, but I don't know Javascript well enough to know what I'm doing.
I took an example of enumerating tables and am trying to add some things to it, but it's not working and I don't know why. Can anyone help me out here?
The code:
Excel.run(function (ctx) {
var tables = ctx.workbook.tables;
var tableNames = ctx.workbook.tables.load("name");
return ctx.sync().then(function() {
console.log("Tables in workbook:");
if (tables.count = 0) {
console.log("No tables found");
} else {
for (var i = 0; i < tableNames.items.length; i++)
{
console.log(i + ": " + tableNames.items[i].name);
}
}
console.log("------------------------");
});
}).catch(function (error) {
console.log(error);
});
In the console log I get this message:
Tables in workbook:
TypeError: Assignment to read-only properties is not allowed in strict mode
I'm basing this off code found here: http://officesnippetexplorer.azurewebsites.net/#/snippets/excel (select 'Table', and snippet 'Get tables in workbook'). Any help would be greatly appreciated!
Thanks,
Zack Barresse
I don't think you mean to change tables.count, do you?
That's what the error is telling you - you have:
if (tables.count = 0) {
but you really wanted:
if (tables.count == 0) {
The first tries to set tables.count to 0, the second tests if tables.count is equal to 0.
This seems like it should be really simple, but for some reason I can't get it to work at all. The following code has no effect whatsoever:
function setExcelImportPrefs() {
with(app.excelImportPreferences){
rangeName = "A1:Z300";
sheetName = "whatever";
tableFormatting = TableFormattingOptions.excelFormattedTable;
}
}
And this doesn't work either:
function setExcelImportPrefs() {
with(app.excelImportPreferences){
app.excelImportPreferences.rangeName = "A1:Z300";
app.excelImportPreferences.sheetName = "whatever";
app.excelImportPreferences.tableFormatting = TableFormattingOptions.excelFormattedTable;
}
}
What am I doing wrong? I've Googled everything, and I'm at my wits end. (Note: I have InDesign CS6, version 8.0)
Edit: Put in a bracket that I accidentally left out when I was copying-and-pasting.
I'm not familiar with these settings, but you seem to have be missing a bracket. Just get rid of the with syntax all together and try
function setExcelImportPrefs() {
app.excelImportPreferences.rangeName = "A1:Z300";
app.excelImportPreferences.sheetName = "whatever";
app.excelImportPreferences.tableFormatting = TableFormattingOptions.excelFormattedTable;
}