Excel JS API: запись, вычисление и загрузка значений из ячеек с помощью пользовательских функций
Намерение состоит в том, чтобы записать формулу (пользовательскую функцию) в ячейку, вычислить ее, загрузить значения и извлечь их в одной функции.
function myFunc() {
Excel.run(function (ctx) {
var fExcel = '=SUM(1,2)';
var fCustom = '=custFunc()';
var rng = ctx.workbook.worksheets.getActiveWorksheet().getRange('A1');
//rng.formulas = [[fExcel]]; // works OK
rng.formulas = [[fCustom]]; // values are #GETTING_DATA
// try different calc calls
rng.load("values");
return ctx.sync().then(function () {
console.log(rng.values);
});
});
}
Для встроенных функций Excel все работает как положено и console
записывает значение 3 после ctx.sync()
, С помощью пользовательских функций (которые отправляют запрос на внешний сервер для вычисления результата) значения '#GETTING_DATA'
, Я пробовал все следующие вещи, прежде чем rng.load("values");
для запуска расчета, но пока ничего не получалось:
rng.calculate();
var s = ctx.workbook.worksheets.getActiveWorksheet(); s.calculate(true);
ctx.workbook.application.calculate('Full');
Есть ли способ запустить расчет пользовательских функций и убедиться, что значения доступны после ctx.sync()
?
1 ответ
Интересный сценарий!
Сегодня это может быть осуществимо, используя событие onCalculate, но предостережение в том, что он будет срабатывать 2 раза, когда ваша пользовательская функция вычисляет.
- Это потому, что ваша пользовательская функция сначала будет показывать #GETTING_DATA, а она будет вычислять в фоновом режиме.
- Это дает пользователю возможность контроля, пока ваши функции все еще оцениваются, что позволяет приложению быть более отзывчивым. Это поведение отличается от пользовательских функций VBA или XLL, которые могут зависать в Excel.
- Когда Excel завершит вычисление, он снова запустит событие вычисления. Это когда результаты возвращаются, решая обещание.
Этот сценарий лаборатории Script должен дать вам представление о том, как это работает:
/*This gist works in combination with any registered Excel JS Custom function*/
$("#set-formulas").click(() => tryCatch(setFormulas));
var rangeToCheck;
async function setFormulas() {
await Excel.run(async (context) => {
//register for event
context.workbook.worksheets.getActiveWorksheet().onCalculated.add(handleCalculate);
//write to grid
const sheet = context.workbook.worksheets.getItem("Sheet1");
rangeToCheck = "A1";
const range = sheet.getRange(rangeToCheck);
range.formulas = [['=CONTOSO.CONTAINS(A1, Days)']];
range.format.autofitColumns();
await context.sync();
});
}
async function handleCalculate(event) {
//read cell
console.log("calc ended - begin");
console.log("Change type of event: " + event.changeType);
console.log("Address of event: " + event.address);
console.log("Source of event: " + event.source);
//Read A1 and log it back to the console
await Excel.run(async (context) => {
//write to grid
const sheet = context.workbook.worksheets.getItem("Sheet1");
const range = sheet.getRange(rangeToCheck);
range.load("values");
await context.sync();
if (range.values.toString() != "GETTING_DATA") {
console.log("Success: " + range.values);
}
});
}
/** Default helper for invoking an action and handling errors. */
async function tryCatch(callback) {
try {
await callback();
} catch (error) {
OfficeHelpers.UI.notify(error);
OfficeHelpers.Utilities.log(error);
}
}