Posted 6 December 2023, 5:17 am EST
Hi,
There no direct feature available for this.
But you can achieve you requirements by following below steps:
- You could load json with doNotRecalculateAfterLoad = true, so that no calculation will happen after load. Refer below snippet.
spread.fromJSON(data,{doNotRecalculateAfterLoad: true});
- Then traverse all sheets cells to create a cellReferences object for async functions only. Refer below snippet.
cellReferences = getMapFormulaReferencesOfCellsForAsync(spread);
function getMapFormulaReferencesOfCellsForAsync( spread){
const info = {};
spread.sheets.forEach( sheet => {
const rows = sheet.getRowCount();
const cols = sheet.getColumnCount();
for( let i = 0; i < rows; i++){
for(let j = 0; j < cols; j++){
const formulaInfo = sheet.getFormulaInformation(i,j);
if(formulaInfo.hasFormula){
const functionName = formulaInfo.formula.slice(0,formulaInfo.formula.indexOf("("));
const customfunction = GC.Spread.CalcEngine.Functions.findGlobalFunction(functionName)
if(customfunction instanceof GC.Spread.CalcEngine.Functions.AsyncFunction){
if(!info[sheet.name()]){
info[sheet.name()] = {};
}
if(!info[sheet.name()][i]){
info[sheet.name()][i] = new Set();
}
info[sheet.name()][i].add(j);
}
}
}
}
})
return info;
}
- Then calculate all sheets using recalcAll method. Refer below snippet.
spread.sheets.forEach( sheet => sheet.recalcAll());
- Within the rangeChanged event callback, remove cell references from the previously created cellReferences object to signify that the calculation has taken place. When the cellReferences object becomes empty, you can proceed to export your file. Refer below snippet.
let flag = true;
designer.getWorkbook().bind(GC.Spread.Sheets.Events.RangeChanged, (e, info) => {
// when function evalution happen
if(cellReferences && info.action == 6){
for( let i = 0; i < info.changedCells.length; i++){
if(cellReferences[info.sheetName] && cellReferences[info.sheetName][info.changedCells[i].row] && cellReferences[info.sheetName][info.changedCells[i].row].has(info.changedCells[i].col)){
cellReferences[info.sheetName][info.changedCells[i].row].delete(info.changedCells[i].col);
if(!cellReferences[info.sheetName][info.changedCells[i].row].size){
delete cellReferences[info.sheetName][info.changedCells[i].row];
}
if(!Object.keys(cellReferences[info.sheetName]).length){
delete cellReferences[info.sheetName];
}
}
if(isAllCalculationDone(cellReferences)){
console.log("All calculation done and now exporting!!")
if(flag){
cellReferences = getMapFormulaReferencesOfCellsForAsync(spread);
flag = false;
return;
}
spread.export(function(blob) { saveAs(blob, "export.xlsx"); },function(){}, {includeFormulas: false});
flag = true;
cellReferences = undefined;
break;
}else{
console.log("Calculation are not done")
}
}
}
});
Note: When you recalculate all sheets, the rangeChanged event will trigger for each sheet, even if the calculation of asynchronous results is not set. It is crucial to handle this case. I’ve addressed this scenario in the provided sample for your reference.
I have attached a sample to refer.
Sample link: https://jscodemine.grapecity.com/share/o3MdlbvISUCH10RAne59yw/?IsEmbed=false&Theme=Unset&PreviewDirection=0&IsEditorShow=true&IsExplorerShow=true&IsPreviewShow=true&IsConsoleShow=true&IsRunBTNShow=false&IsResetBTNShow=false&IsOpenInCodemineBTNShow=false&PanelWidth=20&PanelWidth=50&PanelWidth=30&defaultOpen={"OpenedFileName"%3A["%2Findex.html"%2C"%2Fsrc%2Fapp.js"%2C"%2Fpackage.json"%2C"%2Fsrc%2Fdata.js"]%2C"ActiveFile"%3A"%2Fsrc%2Fapp.js"}
Best regards,
Ankit