Formula evaluation is avaliable on HSSF (xls) and XSSF (xlsx). It's not available with certain restrictions in SXSSF (streaming xlsx).

1 Working with formulas

Formula evaluation code enables you to calculate the result of formulas in Excels sheets.

For performance, a shared instance of FormulaEvaluator for a Workbook is used for all evaluations. The FormulaEvaluator will cache evaluations of dependent cells, so if you have multiple formulas all depending on a cell then subsequent evaluations will be faster.

For example, if we are reading a large Sheet it has no sense to create a FormulaEvaluator for every cell being read. Same way, if we are wirting a large Sheet it has no sense to notify FormulaEvaluator cell has chnaged on every cell write.

While this becomes usefull for perfomance reasons, it may become a problem if we are performing changes on data as cached values will not be recalculated. Let's see a simple example:

Copy
<script>
    var wb = new Ax.ms.Excel();
    var sheet = wb.createSheet("test");
    sheet.getCell("A1").setCellFormula("B1*C1");
    sheet.getCell("B1").setCellValue(3);
    
    sheet.getCell("C1").setCellValue(5);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());

    sheet.getCell("C1").setCellValue(10);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());
</script>
B1*C1 = 15
B1*C1 = 15 (*)

We can see, that we get an invalid result after changing value on cell C1.

1.1 Reset evaluator

We can reset FormulaEvaluator any time by calling resetEvaluator(). A new FormulaEvaluator will be created on next need.

Copy
<script>
    var wb = new Ax.ms.Excel();
    var sheet = wb.createSheet("test");
    sheet.getCell("A1").setCellFormula("B1*C1");
    sheet.getCell("B1").setCellValue(3);
    
    sheet.getCell("C1").setCellValue(5);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());

    wb.resetEvaluator();

    sheet.getCell("C1").setCellValue(10);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());
</script>
B1*C1 = 15
B1*C1 = 30

1.2 Disable evaluator cache

You can disable FormulaEvaluator cache for all operations. Bud doing so, a new FormulaEvaluator is created on every call to getCellValue().

Copy
<script>
    var wb = new Ax.ms.Excel();
    // Disable evaluation cache for all operations
    wb.setEvaluatorCache(false);
    
    var sheet = wb.createSheet("test");
    sheet.getCell("A1").setCellFormula("B1*C1");
    sheet.getCell("B1").setCellValue(3);
    
    sheet.getCell("C1").setCellValue(5);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());

    sheet.getCell("C1").setCellValue(10);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());

    sheet.getCell("C1").setCellValue(20);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());
</script>
B1*C1 = 15
B1*C1 = 30
B1*C1 = 60

This option may have a performance impact on complex computations.

1.3 Full evaluation

To force re-calculating all formulas in a Workbook you can call method evaluate() on a Workbook. This will re-evaluate all formulas.

2 Debugging

In the case you experience formula evaluation problems (Java exceptions or just different results), to support an easy detailed analysis, a special logging of the full evaluation is provided.

The output of this logging may be very large (depends on your EXCEL), so this logging has to be explicitly enabled for each single formula evaluation. Should not be used in production - only for specific development use.

TO DO

This section is incomplete and will be concluded as soon as possible.
Copy
<script>
    var wb = new Ax.ms.Excel();
    // Enable debug -> log will be sent to stdout
    wb.setEvaluatorDebug(true);
    
    var sheet = wb.createSheet("test");
    sheet.getCell("A1").setCellFormula("B1*C1");
    sheet.getCell("B1").setCellValue(3);
    
    sheet.getCell("C1").setCellValue(5);
    console.log(sheet.getCell("A1").getCellFormula() + " = " + sheet.getCell("A1").getCellValue());

</script>
B1*C1 = 15

3 Examples

The following example, generates a excel sheet with multiplication table formula.

Copy
<script>
    // ==================================================================
    // Create an Excel workbook and sheet
    // ==================================================================
    var wb = new Ax.ms.Excel("multiplication");
    
    var sheet = wb.createSheet("sheet1");
    
    // store in var for convenience
    const Color           = Ax.ms.Excel.Color;
    const BorderStyle     = Ax.ms.Excel.BorderStyle;
    const FillPatternType = Ax.ms.Excel.FillPatternType;
    const AxisPosition    = Ax.ms.Excel.AxisPosition;
    const LegendPosition  = Ax.ms.Excel.LegendPosition;
    
    // ==================================================================
    // Show Excel enum constants
    // ==================================================================
    print("Color            =" + Color);
    print("BoderStyle       =" + BorderStyle);
    print("FillPatternType  =" + FillPatternType);
    print("AxisPosition     =" + AxisPosition);
    print("LegendPosition   =" + LegendPosition);
    
    
    // ==================================================================
    // Create a funny style
    // ==================================================================
    
    var style = wb.createCellStyle();
    
    style.setTopBorderColor(Color.GREEN);
    style.setBottomBorderColor(Color.RED);
    style.setLeftBorderColor(Color.BLUE);
    style.setRightBorderColor(Color.YELLOW);
    
    style.setBorderTop(BorderStyle.THICK);
    style.setBorderBottom(BorderStyle.THICK);
    style.setBorderLeft(BorderStyle.THICK);
    style.setBorderRight(BorderStyle.THICK);
            
    
    // ==================================================================
    // Create the first row/col
    // ==================================================================
    
    var row = sheet.createRow(0);
    row.addCell("Multiplication").
        setCellStyle(
            wb.createCellStyle().
            setFillForegroundColor(Color.AQUA).
            setFillPattern(Ax.ms.Excel.FillPatternType.SOLID_FOREGROUND)
        );
    
    // ==================================================================
    // Create the 1st row with factors
    // ==================================================================
    for (var c = 1; c <= 10; c++) {
    	var cell = row.addCell(c);
    	cell.setCellStyle(style);
    }
    
    // ==================================================================
    // Create 10 rows x 10 cols with multiplication formula
    // ==================================================================
    for (var r = 1; r <= 10; r++) {
        var row = sheet.createRow(r);
        var cell = row.addCell(r);
        cell.setCellStyle(style);
        for (var c = 1; c <= 10; c++) {
            row.addCellFormula(Ax.text.String.format("%s*%s", Ax.ms.Excel.toCell(r, 0), Ax.ms.Excel.toCell(0, c)));
        }
    }
    
    // ==================================================================
    // Evaluate first and ensure all fits
    // If evaluate it no done, autosize will not take in account the
    // formulas.
    // ==================================================================
    wb.evaluate();
    wb.setAutoSizeColumns();
    
    // Show value of D4 ... will be 9
    console.log(sheet.getCellValue("D4"));
    
    // ==================================================================
    // Return Excel workbook as a Blob
    // ==================================================================
    return wb;
</script>

Notice that you can perform Excel computation on server side. This means you can obtain computed results from Excel. In the previous example, to obtain the value of cell D4.

Copy
// Show value of D4 ... will be 9
console.log(sheet.getCellValue("D4"));