diff --git a/docs/excel/excel-add-ins-data-validation.md b/docs/excel/excel-add-ins-data-validation.md index 1761601b6..fa51d1cde 100644 --- a/docs/excel/excel-add-ins-data-validation.md +++ b/docs/excel/excel-add-ins-data-validation.md @@ -1,13 +1,13 @@ --- title: Add data validation to Excel ranges -description: Learn how the Excel JavaScript APIs enable your add-in to add automatic data validation to tables, columns, rows, and other ranges in a workbook. -ms.date: 02/16/2022 +description: Use the Excel JavaScript API to programmatically apply and manage data validation rules for ranges, tables, and structured inputs. +ms.date: 09/19/2025 ms.localizationpriority: medium --- # Add data validation to Excel ranges -The Excel JavaScript Library provides APIs to enable your add-in to add automatic data validation to tables, columns, rows, and other ranges in a workbook. To understand the concepts and the terminology of data validation, please see the following articles about how users add data validation through the Excel UI. +Use the Excel JavaScript API to enforce data quality. Apply rules and rely on Excel’s validation UI for prompts and error alerts. This article shows how to define rule types, configure prompts and error alerts, and remove or adjust validation. If you need background on Excel’s built-in validation UI, review these articles. - [Apply data validation to cells](https://support.microsoft.com/office/29fecbcc-d1b9-42c1-9d76-eff3ce5f7249) - [More on data validation](https://support.microsoft.com/office/f38dee73-9900-4ca6-9301-8a5f6e1f0c4c) @@ -15,10 +15,10 @@ The Excel JavaScript Library provides APIs to enable your add-in to add automati ## Programmatic control of data validation -The `Range.dataValidation` property, which takes a [DataValidation](/javascript/api/excel/excel.datavalidation) object, is the entry point for programmatic control of data validation in Excel. There are five properties to the `DataValidation` object: +The `Range.dataValidation` property, which takes a [DataValidation](/javascript/api/excel/excel.datavalidation) object, is the entry point for programmatic control of data validation in Excel. The object has five properties: - `rule` — Defines what constitutes valid data for the range. See [DataValidationRule](/javascript/api/excel/excel.datavalidationrule). -- `errorAlert` — Specifies whether an error pops up if the user enters invalid data, and defines the alert text, title, and style; for example, `information`, `warning`, and `stop`. See [DataValidationErrorAlert](/javascript/api/excel/excel.datavalidationerroralert). +- `errorAlert` — Specifies whether an error pops up if the user enters invalid data, and defines the alert text, title, and style such as `information`, `warning`, and `stop`. See [DataValidationErrorAlert](/javascript/api/excel/excel.datavalidationerroralert). - `prompt` — Specifies whether a prompt appears when the user hovers over the range and defines the prompt message. See [DataValidationPrompt](/javascript/api/excel/excel.datavalidationprompt). - `ignoreBlanks` — Specifies whether the data validation rule applies to blank cells in the range. Defaults to `true`. - `type` — A read-only identification of the validation type, such as WholeNumber, Date, TextLength, etc. It is set indirectly when you set the `rule` property. @@ -26,7 +26,7 @@ The `Range.dataValidation` property, which takes a [DataValidation](/javascript/ > [!NOTE] > Data validation added programmatically behaves just like manually added data validation. In particular, note that data validation is triggered only if the user directly enters a value into a cell or copies and pastes a cell from elsewhere in the workbook and chooses the **Values** paste option. If the user copies a cell and does a plain paste into a range with data validation, validation is not triggered. -## Creating validation rules +## Create validation rules To add data validation to a range, your code must set the `rule` property of the `DataValidation` object in `Range.dataValidation`. This takes a [DataValidationRule](/javascript/api/excel/excel.datavalidationrule) object which has seven optional properties. *No more than one of these properties may be present in any `DataValidationRule` object.* The property that you include determines the type of validation. @@ -38,10 +38,10 @@ The first three `DataValidationRule` properties (i.e., validation rule types) ta - `decimal` — Requires a decimal number in addition to any other validation specified by the `BasicDataValidation` object. - `textLength` — Applies the validation details in the `BasicDataValidation` object to the *length* of the cell's value. -Here is an example of creating a validation rule. Note the following about this code. +The following example creates a validation rule. Key points: -- The `operator` is the binary operator `greaterThan`. Whenever you use a binary operator, the value that the user tries to enter in the cell is the left-hand operand and the value specified in `formula1` is the right-hand operand. So this rule says that only whole numbers that are greater than 0 are valid. -- The `formula1` is a hard-coded number. If you don't know at coding time what the value should be, you can also use an Excel formula (as a string) for the value. For example, "=A3" and "=SUM(A4,B5)" could also be values of `formula1`. +- The `operator` is the binary operator `greaterThan`. Whenever you use a binary operator, the value that the user tries to enter in the cell is the left-hand operand and the value specified in `formula1` is the right-hand operand. This rule says that only whole numbers greater than 0 are valid. +- The `formula1` is a hard-coded number. If you don't know at coding time what the value should be, you can also use an Excel formula as a string (such as "=A3" or "=SUM(A4,B5)"). ```js await Excel.run(async (context) => { @@ -59,9 +59,9 @@ await Excel.run(async (context) => { }); ``` -See [BasicDataValidation](/javascript/api/excel/excel.basicdatavalidation) for a list of the other binary operators. +See [BasicDataValidation](/javascript/api/excel/excel.basicdatavalidation) for other binary operators. -There are also two ternary operators: `between` and `notBetween`. To use these, you must specify the optional `formula2` property. The `formula1` and `formula2` values are the bounding operands. The value that the user tries to enter in the cell is the third (evaluated) operand. The following is an example of using the "Between" operator. +There are also two ternary operators: `between` and `notBetween`. To use these, specify the optional `formula2` property. The `formula1` and `formula2` values are the bounding operands. The value that the user tries to enter in the cell is the third (evaluated) operand. The following is an example of using the "Between" operator. ```js await Excel.run(async (context) => { @@ -106,11 +106,11 @@ await Excel.run(async (context) => { ### List validation rule type -Use the `list` property in the `DataValidationRule` object to specify that the only valid values are those from a finite list. The following is an example. Note the following about this code. +Use the `list` property in the `DataValidationRule` object to constrain values to a finite set. The following code sample demonstrates. Key points: - It assumes that there is a worksheet named "Names" and that the values in the range "A1:A3" are names. -- The `source` property specifies the list of valid values. The string argument refers to a range containing the names. You can also assign a comma-delimited list; for example: "Sue, Ricky, Liz". -- The `inCellDropDown` property specifies whether a drop-down control will appear in the cell when the user selects it. If set to `true`, then the drop-down appears with the list of values from the `source`. +- The `source` property specifies the list of valid values. The string argument refers to a range containing the names. You can also assign a comma-delimited list such as "Sue, Ricky, Liz". +- The `inCellDropDown` property specifies whether a drop-down control appears in the cell when the user selects it. If `true`, the drop-down appears with the list of values from the `source`. ```js await Excel.run(async (context) => { @@ -131,11 +131,12 @@ await Excel.run(async (context) => { ### Custom validation rule type -Use the `custom` property in the `DataValidationRule` object to specify a custom validation formula. The following is an example. Note the following about this code. +Use the `custom` property to specify a custom validation formula. The following is an example. Key points: -- It assumes there is a two-column table with columns **Athlete Name** and **Comments** in the A and B columns of the worksheet. -- To reduce verbosity in the **Comments** column, it makes data that includes the athlete's name invalid. -- `SEARCH(A2,B2)` returns the starting position, in string in B2, of the string in A2. If A2 is not contained in B2, it does not return a number. `ISNUMBER()` returns a boolean. So the `formula` property says that valid data for the **Comment** column is data that does not include the string in the **Athlete Name** column. +- It assumes a there is two-column table with columns **Athlete Name** and **Comments** in the A and B columns of the worksheet. +- To reduce verbosity in the **Comments** column, the rule makes data that includes the athlete's name invalid. +- `SEARCH(A2,B2)` returns the starting position in B2 of the string in A2. If A2 isn't contained in B2, it doesn't return a number. +- `ISNUMBER()` returns a boolean. So the `formula` property says that valid data for **Comments** is data that doesn't include the **Athlete Name** string. ```js await Excel.run(async (context) => { @@ -154,7 +155,7 @@ await Excel.run(async (context) => { ## Create validation error alerts -You can a create custom error alert that appears when a user tries to enter invalid data in a cell. The following is a simple example. Note the following about this code. +Create an error alert to guide the user when invalid data is entered. The following example creates a basic alert. Key points: - The `style` property determines whether the user gets an informational alert, a warning, or a "stop" alert. Only `stop` actually prevents the user from adding invalid data. The pop-ups for `warning` and `information` have options that allow the user enter the invalid data anyway. - The `showAlert` property defaults to `true`. This means that Excel will pop-up a generic alert (of type `stop`) unless you create a custom alert which either sets `showAlert` to `false` or sets a custom message, title, and style. This code sets a custom message and title. @@ -181,7 +182,7 @@ For more information, see [DataValidationErrorAlert](/javascript/api/excel/excel ## Create validation prompts -You can create an instructional prompt that appears when a user hovers over, or selects, a cell to which data validation has been applied. The following is an example. +Create an instructional prompt that appears when the user selects the cell. This example tells the user about the positive number validation before they enter data. ```js await Excel.run(async (context) => { @@ -207,16 +208,21 @@ For more information, see [DataValidationPrompt](/javascript/api/excel/excel.dat To remove data validation from a range, call the [Range.dataValidation.clear()](/javascript/api/excel/excel.datavalidation#excel-excel-datavalidation-clear-member(1)) method. ```js -myrange.dataValidation.clear() +myrange.dataValidation.clear(); ``` -It isn't necessary that the range you clear is exactly the same range as a range on which you added data validation. If it isn't, only the overlapping cells, if any, of the two ranges are cleared. +The range you clear doesn’t need to precisely match the range on which you added data validation. If the two ranges aren't an exact match, only overlapping cells are cleared. > [!NOTE] > Clearing data validation from a range will also clear any data validation that a user has added manually to the range. +## Next steps + +- Combine validation with events: [Events](excel-add-ins-events.md). +- Add [conditional formatting](excel-add-ins-conditional-formatting.md) for stronger visual cues. + ## See also - [Excel JavaScript object model in Office Add-ins](excel-add-ins-core-concepts.md) - [DataValidation Object (JavaScript API for Excel)](/javascript/api/excel/excel.datavalidation) -- [Range Object (JavaScript API for Excel)](/javascript/api/excel/excel.range) +- [Range Object (JavaScript API for Excel)](/javascript/api/excel/excel.range) \ No newline at end of file diff --git a/docs/excel/excel-add-ins-delay-in-cell-edit.md b/docs/excel/excel-add-ins-delay-in-cell-edit.md index 734b17fe5..27152076f 100644 --- a/docs/excel/excel-add-ins-delay-in-cell-edit.md +++ b/docs/excel/excel-add-ins-delay-in-cell-edit.md @@ -1,17 +1,42 @@ --- title: Delay execution while cell is being edited -description: Learn how to delay the execution of the Excel.run function when a cell is being edited. -ms.date: 02/16/2022 +description: Defer an Excel.run batch until the user leaves cell edit mode instead of failing with an error. +ms.date: 09/19/2025 ms.localizationpriority: medium --- - # Delay execution while cell is being edited -`Excel.run` has an overload that takes in a [Excel.RunOptions](/javascript/api/excel/excel.runoptions) object. This contains a set of properties that affect platform behavior when the function runs. The following property is currently supported. +When a user is actively editing a cell, some add-in operations may fail immediately. Use the `delayForCellEdit` option to queue the batch until the user exits cell edit mode instead of throwing an error. + +`Excel.run` has an overload that takes an [Excel.RunOptions](/javascript/api/excel/excel.runoptions) object. It supports the following property relevant to this scenario. + +- `delayForCellEdit`: When `true`, Excel queues the batch until the user exits cell edit mode. When `false`, the batch fails immediately if the user is editing. The default value is `false`. + +## Behavior comparison + +| User editing? | `delayForCellEdit = false` (default) | `delayForCellEdit = true` | +|---------------|------------------------------------|--------------------------| +| No | Batch runs immediately | Batch runs immediately | +| Yes | Batch fails (`InvalidOperation` error) | Batch waits; then runs after edit is committed or canceled | -- `delayForCellEdit`: Determines whether Excel delays the batch request until the user exits cell edit mode. When `true`, the batch request is delayed and runs when the user exits cell edit mode. When `false`, the batch request automatically fails if the user is in cell edit mode (causing an error to reach the user). The default behavior with no `delayForCellEdit` property specified is equivalent to when it is `false`. +## Example ```js -await Excel.run({ delayForCellEdit: true }, async (context) => { ... }); +await Excel.run({ delayForCellEdit: true }, async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + const range = sheet.getRange("A1"); + range.values = [["Updated while user was editing elsewhere"]]; + await context.sync(); +}); ``` + +## Guidance + +- Use `delayForCellEdit` only when user-initiated commands may overlap active cell editing, such as with a ribbon button that triggers a bulk update. +- Consider showing a status indicator in your add-in if queued work may be lengthy. +- Avoid chaining multiple long-running delayed batches. This creates a perceived lag for your users. + +## Next steps + +Explore related user-state strategies in [Events](excel-add-ins-events.md), such as reacting to selection changes, and combine with `delayForCellEdit` to improve your add-in's robustness. diff --git a/docs/excel/excel-add-ins-multiple-ranges.md b/docs/excel/excel-add-ins-multiple-ranges.md index 5782c1cb9..f79e092dc 100644 --- a/docs/excel/excel-add-ins-multiple-ranges.md +++ b/docs/excel/excel-add-ins-multiple-ranges.md @@ -1,30 +1,34 @@ --- title: Work with multiple ranges simultaneously in Excel add-ins description: Learn how the Excel JavaScript library enables your add-in to perform operations, and set properties, on multiple ranges simultaneously. -ms.date: 02/16/2022 +ms.date: 09/22/2025 ms.localizationpriority: medium --- # Work with multiple ranges simultaneously in Excel add-ins -The Excel JavaScript library enables your add-in to perform operations, and set properties, on multiple ranges simultaneously. The ranges do not have to be contiguous. In addition to making your code simpler, this way of setting a property runs much faster than setting the same property individually for each of the ranges. +You can apply operations or set properties on several ranges at once, even if they're not contiguous. This makes code shorter and more efficient when compared to accessing each range separately. -## RangeAreas +## Key points + +- Use `RangeAreas` to read or set the same thing on several separate ranges in one call. +- A property is `null` unless all member ranges share the same value. +- Set a property once on the `RangeAreas` object instead of looping, unless each range needs different logic. +- Avoid large `RangeAreas` objects made of many single cells. Narrow first with `getSpecialCells` or other filters. +- Be careful with whole columns or rows. For more details, see [Read or write to an unbounded range](excel-add-ins-ranges-unbounded.md). -A set of (possibly discontiguous) ranges is represented by a [RangeAreas](/javascript/api/excel/excel.rangeareas) object. It has properties and methods similar to the `Range` type (many with the same, or similar, names), but adjustments have been made to: +## RangeAreas -- The data types for properties and the behavior of the setters and getters. -- The data types of method parameters and the method behaviors. -- The data types of method return values. +A [RangeAreas](/javascript/api/excel/excel.rangeareas) object represents a set of ranges that may not touch. It shares many members with `Range`, with a few differences in how values are returned. -Some examples: +Examples: -- `RangeAreas` has an `address` property that returns a comma-delimited string of range addresses, instead of just one address as with the `Range.address` property. -- `RangeAreas` has a `dataValidation` property that returns a `DataValidation` object that represents the data validation of all the ranges in the `RangeAreas`, if it is consistent. The property is `null` if identical `DataValidation` objects are not applied to all the all the ranges in the `RangeAreas`. This is a general, but not universal, principle with the `RangeAreas` object: *If a property does not have consistent values on all the all the ranges in the `RangeAreas`, then it is `null`.* See [Read properties of RangeAreas](#read-properties-of-rangeareas) for more information and some exceptions. -- `RangeAreas.cellCount` gets the total number of cells in all the ranges in the `RangeAreas`. -- `RangeAreas.calculate` recalculates the cells of all the ranges in the `RangeAreas`. -- `RangeAreas.getEntireColumn` and `RangeAreas.getEntireRow` return another `RangeAreas` object that represents all of the columns (or rows) in all the ranges in the `RangeAreas`. For example, if the `RangeAreas` represents "A1:C4" and "F14:L15", then `RangeAreas.getEntireColumn` returns a `RangeAreas` object that represents "A:C" and "F:L". -- `RangeAreas.copyFrom` can take either a `Range` or a `RangeAreas` parameter representing the source ranges of the copy operation. +- `address` returns one comma-delimited string of all addresses. +- `dataValidation` returns a single object only if every range has the same rule, otherwise it returns `null`. +- `cellCount` is the total cells across all ranges. +- `calculate` recalculates all cells in the set. +- `getEntireColumn` and `getEntireRow` return a new `RangeAreas` spanning full columns or rows for each member. +- `copyFrom` accepts either a `Range` or a `RangeAreas` as the source. ### Complete list of Range members that are also available on RangeAreas @@ -78,9 +82,10 @@ The `RangeAreas` type has some properties and methods that are not on the `Range ## Create RangeAreas -You can create `RangeAreas` object in two basic ways: +You can create a `RangeAreas` object in multiple ways. The following list includes some examples. - Call `Worksheet.getRanges()` and pass it a string with comma-delimited range addresses. If any range you want to include has been made into a [NamedItem](/javascript/api/excel/excel.nameditem), you can include the name, instead of the address, in the string. +- Call `Range.getSpecialCells()` and return a `RangeAreas` object with cells of a specific type, such as cells that contain formulas, data validation, or conditional formatting. - Call `Workbook.getSelectedRanges()`. This method returns a `RangeAreas` representing all the ranges that are selected on the currently active worksheet. Once you have a `RangeAreas` object, you can create others using the methods on the object that return `RangeAreas` such as `getOffsetRangeAreas` and `getIntersection`. @@ -89,7 +94,7 @@ Once you have a `RangeAreas` object, you can create others using the methods on > You cannot directly add additional ranges to a `RangeAreas` object. For example, the collection in `RangeAreas.areas` does not have an `add` method. > [!WARNING] -> Do not attempt to directly add or delete members of the the `RangeAreas.areas.items` array. This will lead to undesirable behavior in your code. For example, it is possible to push an additional `Range` object onto the array, but doing so will cause errors because `RangeAreas` properties and methods behave as if the new item isn't there. For example, the `areaCount` property does not include ranges pushed in this way, and the `RangeAreas.getItemAt(index)` throws an error if `index` is larger than `areasCount-1`. Similarly, deleting a `Range` object in the `RangeAreas.areas.items` array by getting a reference to it and calling its `Range.delete` method causes bugs: although the `Range` object *is* deleted, the properties and methods of the parent `RangeAreas` object behave, or try to, as if it is still in existence. For example, if your code calls `RangeAreas.calculate`, Office will try to calculate the range, but will error because the range object is gone. +> Do not attempt to directly add or delete members of the `RangeAreas.areas.items` array. This will lead to undesirable behavior in your code. For example, it is possible to push an additional `Range` object onto the array, but doing so will cause errors because `RangeAreas` properties and methods behave as if the new item isn't there. For example, the `areaCount` property does not include ranges pushed in this way, and the `RangeAreas.getItemAt(index)` throws an error if `index` is larger than `areasCount-1`. Similarly, deleting a `Range` object in the `RangeAreas.areas.items` array by getting a reference to it and calling its `Range.delete` method causes bugs: although the `Range` object *is* deleted, the properties and methods of the parent `RangeAreas` object behave, or try to, as if it is still in existence. For example, if your code calls `RangeAreas.calculate`, Office will try to calculate the range, but will error because the range object is gone. ## Set properties on multiple ranges @@ -112,6 +117,24 @@ This example applies to scenarios in which you can hard code the range addresses - The code runs in the context of a known template. - The code runs in the context of imported data where the schema of the data is known. +## Combine `RangeAreas` with `getSpecialCells` + +Filter a `RangeAreas` down to just the cells that match a criterion, such as formulas, before applying formatting or validation. + +```js +await Excel.run(async (context) => { + const sheet = context.workbook.worksheets.getActiveWorksheet(); + + // Two discontiguous vertical bands. + const targets = sheet.getRanges("A1:A100, C1:C100"); + + // Narrow to only the formula cells within those bands. + const formulaCells = targets.getSpecialCells(Excel.SpecialCellType.formulas); + formulaCells.format.fill.color = "lightYellow"; + await context.sync(); +}); +``` + ## Get special cells from multiple ranges The `getSpecialCells` and `getSpecialCellsOrNullObject` methods on the `RangeAreas` object work analogously to methods of the same name on the `Range` object. These methods return the cells with the specified characteristic from all of the ranges in the `RangeAreas.areas` collection. For more details on special cells, see [Find special cells within a range](excel-add-ins-ranges-special-cells.md). @@ -141,11 +164,11 @@ await Excel.run(async (context) => { }); ``` -Things get more complicated when consistency isn't possible. The behavior of `RangeAreas` properties follows these three principles: +Since property values can differ, keep these simple rules in mind. -- A boolean property of a `RangeAreas` object returns `false` unless the property is true for all the member ranges. -- Non-boolean properties, with the exception of the `address` property, return `null` unless the corresponding property on all the member ranges has the same value. -- The `address` property returns a comma-delimited string of the addresses of the member ranges. +- Boolean properties are `true` only if they're true in all ranges, otherwise they're `false`. +- `address` always returns the comma-delimited addresses string. +- Other properties are `null` unless all ranges share the same value. For example, the following code creates a `RangeAreas` in which only one range is an entire column and only one is filled with pink. The console will show `null` for the fill color, `false` for the `isEntireRow` property, and "Sheet1!F3:F5, Sheet1!H:H" (assuming the sheet name is "Sheet1") for the `address` property. @@ -170,3 +193,4 @@ await Excel.run(async (context) => { - [Fundamental programming concepts with the Excel JavaScript API](../reference/overview/excel-add-ins-reference-overview.md) - [Read or write to a large range using the Excel JavaScript API](excel-add-ins-ranges-large.md) +- [Read or write to an unbounded range using the Excel JavaScript API](excel-add-ins-ranges-unbounded.md) diff --git a/docs/excel/excel-add-ins-ranges-large.md b/docs/excel/excel-add-ins-ranges-large.md index b2f68d1ba..ed565fc3c 100644 --- a/docs/excel/excel-add-ins-ranges-large.md +++ b/docs/excel/excel-add-ins-ranges-large.md @@ -1,28 +1,47 @@ --- title: Read or write to large ranges using the Excel JavaScript API -description: Learn how to read or write to large ranges with the Excel JavaScript API. -ms.date: 04/02/2021 +description: Learn strategies to efficiently read or write large Excel ranges with the Excel JavaScript API, without hitting resource limits. +ms.date: 09/22/2025 ms.topic: best-practice ms.localizationpriority: medium --- # Read or write to a large range using the Excel JavaScript API -This article describes how to handle reading and writing to large ranges with the Excel JavaScript API. +Use these patterns to read or write large ranges, while avoiding resource limit errors. -## Run separate read or write operations for large ranges +- Split big ranges into smaller blocks. Don't load or write everything at once. +- Load only what you need (for example, just `values` instead of `values,numberFormat,formulas`). +- Use `getSpecialCells` and `RangeAreas` to work with scattered cells instead of a large range. +- If you encounter a limit error, retry with a smaller block size. +- Apply formatting after the data is in place. -If a range contains a large number of cells, values, number formats, or formulas, it may not be possible to run API operations on that range. The API will always make a best attempt to run the requested operation on a range (i.e., to retrieve or write the specified data), but attempting to perform read or write operations for a large range may result in an API error due to excessive resource utilization. To avoid such errors, we recommend that you run separate read or write operations for smaller subsets of a large range, instead of attempting to run a single read or write operation on a large range. +## When to split a large range -For details on the system limitations, see the "Excel add-ins" section of [Resource limits and performance optimization for Office Add-ins](../concepts/resource-limits-and-performance-optimization.md#excel-add-ins). +| Scenario | Sign you should split the range | Approach | +|----------|----------------------|----------| +| Reading millions of cells | Timeout or resource error | Read in row or column blocks. Start with 5k–20k rows. | +| Writing a large result set | Single `values` write fails | Write in row blocks (with same column count for each block). | +| Sparse updates | Many distant cells | Build combined address string with `getRanges` and `RangeAreas`. | +| Writing data and formatting | Formatting slows Excel | Write values first, format afterward. | -### Conditional formatting of ranges +## Defer formatting & calculations -Ranges can have formats applied to individual cells based on conditions. For more information about this, see [Apply conditional formatting to Excel ranges](excel-add-ins-conditional-formatting.md). +Formatting and calculation-heavy operations, such as conditional formats or formula writes, add time on large areas. Consider: + +- First write raw values (plain numbers or text), then add formulas or formats in a second pass. +- Use `setDirty` only on necessary recalculation scopes. +- Limit conditional formats to used rows instead of entire column references (such as `A2:A5000` instead of `A:A`) with `getUsedRange`. + +## Next steps + +- Learn about related [resource limits and performance optimization](../concepts/resource-limits-and-performance-optimization.md#excel-add-ins). +- Handle large but sparse selections with [multiple ranges](excel-add-ins-multiple-ranges.md). +- Compare with patterns for [unbounded ranges](excel-add-ins-ranges-unbounded.md). +- Explore special cell targeting in [find special cells](excel-add-ins-ranges-special-cells.md). ## See also - [Excel JavaScript object model in Office Add-ins](excel-add-ins-core-concepts.md) - [Work with cells using the Excel JavaScript API](excel-add-ins-cells.md) -- [Read or write to an unbounded range using the Excel JavaScript API](excel-add-ins-ranges-unbounded.md) -- [Work with multiple ranges simultaneously in Excel add-ins](excel-add-ins-multiple-ranges.md) +- [Apply conditional formatting to Excel ranges](excel-add-ins-conditional-formatting.md) diff --git a/docs/excel/excel-add-ins-ranges-precedents-dependents.md b/docs/excel/excel-add-ins-ranges-precedents-dependents.md index 2194db3e5..a62466311 100644 --- a/docs/excel/excel-add-ins-ranges-precedents-dependents.md +++ b/docs/excel/excel-add-ins-ranges-precedents-dependents.md @@ -1,18 +1,27 @@ --- title: Work with formula precedents and dependents using the Excel JavaScript API description: Learn how to use the Excel JavaScript API to retrieve formula precedents and dependents. -ms.date: 05/30/2024 +ms.date: 09/22/2025 ms.localizationpriority: medium --- # Get formula precedents and dependents using the Excel JavaScript API -Excel formulas often contain references to other cells in the same worksheet or workbook. These cross-cell references are known as "precedents" and "dependents". A precedent is a cell that provides data to a formula. A dependent is a cell that contains a formula which refers to other cells. To learn more about features in the Excel UI related to precedents and dependents, such as **Trace Precedents** and **Trace Dependents**, see [Display the relationships between formulas and cells](https://support.microsoft.com/office/a59bef2b-3701-46bf-8ff1-d3518771d507). +Excel formulas often refer to other cells. Those input cells are the formula's "precedents". Any formula cell that depends on other cells is a "dependent" of those cells. To learn more about the related Excel UI features, see [Display the relationships between formulas and cells](https://support.microsoft.com/office/a59bef2b-3701-46bf-8ff1-d3518771d507). -A precedent cell may have its own precedent cells. Every precedent cell in this chain of precedents is still a precedent of the original cell. The same relationship exists for dependents. Any cell affected by another cell is a dependent of that cell. A "direct precedent" is the first preceding group of cells in this sequence, similar to the concept of parents in a parent-child relationship. A "direct dependent" is the first dependent group of cells in a sequence, similar to children in a parent-child relationship. +Chains of precedents and dependents can form. A precedent can itself have precedents, and so on. The same idea applies to dependents. A "direct precedent" or "direct dependent" is only the first level: the cells a formula points to, or the cells that point straight to a formula. This article provides code samples that retrieve the precedents and dependents of formulas using the Excel JavaScript API. For the complete list of properties and methods that the `Range` object supports, see [Range Object (JavaScript API for Excel)](/javascript/api/excel/excel.range). +## Key points + +- Use `getPrecedents` or `getDependents` to get all related cells. Use `getDirectPrecedents` or `getDirectDependents` to get only the first level. +- Both APIs return a `WorkbookRangeAreas` object. It groups addresses by worksheet. Look in each `areas.items` list for the individual `Range` objects. +- Very large sets, such as thousands of cells, can be slow. Start with the direct methods or narrow the selection first. +- These APIs do not cross workbook boundaries. +- If there are no related cells, an `ItemNotFound` error is thrown. Catch it and show a friendly message. +- If you highlight cells, give users a way to clear the formatting. + ## Get the precedents of a formula Locate a formula's precedent cells with [Range.getPrecedents](/javascript/api/excel/excel.range#excel-excel-range-getprecedents-member(1)). `Range.getPrecedents` returns a `WorkbookRangeAreas` object. This object contains the addresses of all the precedents in the workbook. It has a separate `RangeAreas` object for each worksheet containing at least one formula precedent. To learn more about the `RangeAreas` object, see [Work with multiple ranges simultaneously in Excel add-ins](excel-add-ins-multiple-ranges.md). @@ -65,7 +74,7 @@ await Excel.run(async (context) => { ``` > [!NOTE] -> The `Range.getPrecedents` and `Range.getDirectPrecedents` methods return an `ItemNotFound` error if no precedent cells are found. +> The `Range.getPrecedents` and `Range.getDirectPrecedents` methods return an `ItemNotFound` error if no precedent cells are found. Catch this and provide a user-friendly message. ## Get the dependents of a formula @@ -119,7 +128,7 @@ await Excel.run(async (context) => { ``` > [!NOTE] -> The `Range.getDependents` and `Range.getDirectDependents` methods return an `ItemNotFound` error if no dependent cells are found. +> The `Range.getDependents` and `Range.getDirectDependents` methods return an `ItemNotFound` error if no dependent cells are found. Catch this and provide a user-friendly message. ## See also diff --git a/docs/excel/excel-add-ins-ranges-special-cells.md b/docs/excel/excel-add-ins-ranges-special-cells.md index cb02df580..985447011 100644 --- a/docs/excel/excel-add-ins-ranges-special-cells.md +++ b/docs/excel/excel-add-ins-ranges-special-cells.md @@ -1,13 +1,23 @@ --- title: Find special cells within a range using the Excel JavaScript API description: Learn how to use the Excel JavaScript API to find special cells, such as cells with formulas, errors, or numbers. -ms.date: 02/17/2022 +ms.date: 09/19/2025 ms.localizationpriority: medium --- # Find special cells within a range using the Excel JavaScript API -This article provides code samples that find special cells within a range using the Excel JavaScript API. For the complete list of properties and methods that the `Range` object supports, see [Excel.Range class](/javascript/api/excel/excel.range). +Use the Excel JavaScript API to quickly locate cells with formulas, constants, errors, or other characteristics so you can audit, refactor, or apply formatting efficiently. This article shows how to use `Range.getSpecialCells` and `Range.getSpecialCellsOrNullObject`, when to choose each, and how to further narrow results with cell value types. For the full set of properties and methods that the `Range` object supports, see [Excel.Range class](/javascript/api/excel/excel.range). + +## Quick reference + +| Goal | Use this method | If target might not exist | Result type | Error behavior | +|------|-----------------|---------------------------|-------------|----------------| +| Require at least one matching cell | `getSpecialCells` | N/A | `RangeAreas` | Throws `ItemNotFound` if none exist | +| Optionally act only if matches exist | `getSpecialCellsOrNullObject` | Check `isNullObject` after `context.sync()` | `RangeAreas` proxy | No error, returns `isNullObject = true` | + +> [!TIP] +> Treat `getSpecialCells` like an assertion. Use `getSpecialCellsOrNullObject` when the absence of matches is a valid result, not an error. ## Find ranges with special cells @@ -21,10 +31,10 @@ getSpecialCells(cellType: Excel.SpecialCellType, cellValueType?: Excel.SpecialCe getSpecialCellsOrNullObject(cellType: Excel.SpecialCellType, cellValueType?: Excel.SpecialCellValueType): Excel.RangeAreas; ``` -The following code sample uses the `getSpecialCells` method to find all the cells with formulas. About this code, note: +The following code sample uses `getSpecialCells` to find all cells with formulas. Please note: -- It limits the part of the sheet that needs to be searched by first calling `Worksheet.getUsedRange` and calling `getSpecialCells` for only that range. -- The `getSpecialCells` method returns a `RangeAreas` object, so all of the cells with formulas will be colored pink even if they are not all contiguous. +- The search scope is restricted for better performance by calling `worksheet.getUsedRange()` first. +- `getSpecialCells` returns a single `RangeAreas` object, so non‑contiguous matches can be formatted in one operation. ```js await Excel.run(async (context) => { @@ -62,7 +72,7 @@ await Excel.run(async (context) => { }); ``` -For simplicity, all other code samples in this article use the `getSpecialCells` method instead of `getSpecialCellsOrNullObject`. +For simplicity, the remaining samples in this article use `getSpecialCells`. ## Narrow the target cells with cell value types @@ -76,14 +86,16 @@ The `Range.getSpecialCells()` and `Range.getSpecialCellsOrNullObject()` methods The `Excel.SpecialCellValueType` enum has these four basic types (in addition to the other combined values described later in this section): - `Excel.SpecialCellValueType.errors` -- `Excel.SpecialCellValueType.logical` (which means boolean) +- `Excel.SpecialCellValueType.logical` (which means Boolean) - `Excel.SpecialCellValueType.numbers` - `Excel.SpecialCellValueType.text` -The following code sample finds special cells that are numerical constants and colors those cells pink. About this code, note: +The next sample finds numerical constants and colors them pink. -- It only highlights cells that have a literal number value. It won't highlight cells that have a formula (even if the result is a number) or a boolean, text, or error state cells. -- To test the code, be sure the worksheet has some cells with literal number values, some with other kinds of literal values, and some with formulas. +Key points: + +- Only literal numeric constants are targeted (not formulas that evaluate to numbers, nor Booleans, text, or error cells). +- To test, populate the sheet with literal number values, other kinds of literal values, and formulas. ```js await Excel.run(async (context) => { @@ -100,7 +112,7 @@ await Excel.run(async (context) => { ### Test for multiple cell value types -Sometimes you need to operate on more than one cell value type, such as all text-valued and all boolean-valued (`Excel.SpecialCellValueType.logical`) cells. The `Excel.SpecialCellValueType` enum has values with combined types. For example, `Excel.SpecialCellValueType.logicalText` targets all boolean and all text-valued cells. `Excel.SpecialCellValueType.all` is the default value, which does not limit the cell value types returned. The following code sample colors all cells with formulas that produce number or boolean value. +Sometimes you need to operate on more than one cell value type, such as all text-valued and all Boolean-valued (`Excel.SpecialCellValueType.logical`) cells. The `Excel.SpecialCellValueType` enum has values with combined types. For example, `Excel.SpecialCellValueType.logicalText` targets all Boolean and all text-valued cells. `Excel.SpecialCellValueType.all` is the default value, which does not limit the cell value types returned. The following code sample colors all cells with formulas that produce number or Boolean value. ```js await Excel.run(async (context) => { @@ -115,9 +127,12 @@ await Excel.run(async (context) => { }); ``` +## Next steps + +- Combine special-cell queries with [string search](excel-add-ins-ranges-string-match.md) for richer auditing. +- Apply formatting, comments, or data validation to the resulting [RangeAreas](excel-add-ins-multiple-ranges.md) object. + ## See also - [Excel JavaScript object model in Office Add-ins](excel-add-ins-core-concepts.md) - [Work with cells using the Excel JavaScript API](excel-add-ins-cells.md) -- [Find a string using the Excel JavaScript API](excel-add-ins-ranges-string-match.md) -- [Work with multiple ranges simultaneously in Excel add-ins](excel-add-ins-multiple-ranges.md) diff --git a/docs/excel/performance.md b/docs/excel/performance.md index 2ec52ec86..60ef08f5f 100644 --- a/docs/excel/performance.md +++ b/docs/excel/performance.md @@ -1,25 +1,37 @@ --- title: Excel JavaScript API performance optimization -description: Optimize Excel add-in performance using the JavaScript API. -ms.date: 09/03/2025 +description: Optimize Excel add-in performance using the Excel JavaScript API with batching, fewer objects, and reduced payload size. +ms.date: 09/19/2025 ms.topic: best-practice ms.localizationpriority: medium --- # Performance optimization using the Excel JavaScript API -There are multiple ways that you can perform common tasks with the Excel JavaScript API. You'll find significant performance differences between various approaches. This article provides guidance and code samples to show you how to perform common tasks efficiently using Excel JavaScript API. +Write faster, more scalable Excel add-ins by minimizing processes, batching functions, and reducing payload size. This article shows patterns, anti-patterns, and code samples to help you optimize common operations. + +## Quick improvements + +Apply these strategies first for the largest immediate impact. + +- Batch loads and writes: group property `load` calls, then make a single `context.sync()`. +- Minimize object creation: operate on block ranges instead of many single-cell ranges. +- Write data in arrays, then assign once to a target range. +- Suspend screen updating or calculation only around large changes. +- Avoid per-iteration `Excel.run` or `context.sync()` inside loops. +- Reuse worksheet, table, and range objects instead of re-querying inside loops. +- Keep payloads below size limits by chunking or aggregating before assignment. > [!IMPORTANT] > Many performance issues can be addressed through recommended usage of `load` and `sync` calls. See the "Performance improvements with the application-specific APIs" section of [Resource limits and performance optimization for Office Add-ins](../concepts/resource-limits-and-performance-optimization.md#performance-improvements-with-the-application-specific-apis) for advice on working with the application-specific APIs in an efficient way. ## Suspend Excel processes temporarily -Excel has a number of background tasks reacting to input from both users and your add-in. Some of these Excel processes can be controlled to yield a performance benefit. This is especially helpful when your add-in deals with large data sets. +Excel performs background tasks that react to user input and add-in actions. Pausing selected processes can improve performance for large operations. ### Suspend calculation temporarily -If you are trying to perform an operation on a large number of cells (for example, setting the value of a huge range object) and you don't mind suspending the calculation in Excel temporarily while your operation finishes, we recommend that you suspend calculation until the next `context.sync()` is called. +If you need to update a large range (such as to assign values and then recalculate dependent formulas) and interim recalculation results aren't needed, suspend calculation temporarily until the next `context.sync()`. See the [Application Object](/javascript/api/excel/excel.application) reference documentation for information about how to use the `suspendApiCalculationUntilNextSync()` API to suspend and reactivate calculations in a very convenient way. The following code demonstrates how to suspend calculation temporarily. @@ -62,22 +74,27 @@ await Excel.run(async (context) => { }); ``` -Please note that only formula calculations are suspended. Any altered references are still rebuilt. For example, renaming a worksheet still updates any references in formulas to that worksheet. +Only formula calculations are suspended. Any altered references are still rebuilt. For example, renaming a worksheet still updates any references in formulas to that worksheet. ### Suspend screen updating -Excel displays changes your add-in makes approximately as they happen in the code. For large, iterative data sets, you may not need to see this progress on the screen in real-time. `Application.suspendScreenUpdatingUntilNextSync()` pauses visual updates to Excel until the add-in calls `context.sync()`, or until `Excel.run` ends (implicitly calling `context.sync`). Be aware, Excel will not show any signs of activity until the next sync. Your add-in should either give users guidance to prepare them for this delay or provide a status bar to demonstrate activity. +Excel displays changes as they occur. For large, iterative updates, suppress intermediate screen updates. `Application.suspendScreenUpdatingUntilNextSync()` pauses visual updates until the next `context.sync()` or the end of `Excel.run`. Provide your users with feedback such as status text or a progress bar, because the UI appears idle during suspension. > [!NOTE] > Don't call `suspendScreenUpdatingUntilNextSync` repeatedly (such as in a loop). Repeated calls will cause the Excel window to flicker. ### Enable and disable events -Performance of an add-in may be improved by disabling events. A code sample showing how to enable and disable events is in the [Work with Events](excel-add-ins-events.md#enable-and-disable-events) article. +You can sometimes improve performance by disabling events. A code sample showing how to enable and disable events is in the [Work with Events](excel-add-ins-events.md#enable-and-disable-events) article. ## Importing data into tables -When trying to import a huge amount of data directly into a [Table](/javascript/api/excel/excel.table) object directly (for example, by using `TableRowCollection.add()`), you might experience slow performance. If you are trying to add a new table, you should fill in the data first by setting `range.values`, and then call `worksheet.tables.add()` to create a table over the range. If you are trying to write data into an existing table, write the data into a range object via `table.getDataBodyRange()`, and the table will expand automatically. +When you import large datasets directly into a [Table](/javascript/api/excel/excel.table), such as repeatedly calling `TableRowCollection.add()`, performance can degrade. Instead, take the following approach: + +1. Write the entire 2D array to a range with `range.values`. +2. Create the table over that populated range (`worksheet.tables.add()`). + +For existing tables, set values on `table.getDataBodyRange()` in bulk. The table expands automatically. Here is an example of this approach: @@ -107,19 +124,19 @@ await Excel.run(async (context) => { ## Payload size limit best practices -The Excel JavaScript API has size limitations for API calls. **Excel on the web** has a payload size limit for requests and responses of **5MB**, and an API returns a `RichAPI.Error` error if this limit is exceeded. On all platforms, a range is limited to five million cells for get operations. Large ranges typically exceed both of these limitations. +The Excel JavaScript API has size limitations for API calls. **Excel on the web** limits requests and responses to **5 MB**. The API returns a `RichAPI.Error` error if this limit is exceeded. On all platforms, a range is limited to five million cells for get operations. Large ranges often exceed both limits. -The payload size of a request is a combination of the following three components. +The payload size of a request combines: -* The number of API calls -* The number of objects, such as `Range` objects -* The length of the value to set or get +- The number of API calls. +- The number of objects, such as `Range` objects. +- The length of the value to set or get. -If an API returns the `RequestPayloadSizeLimitExceeded` error, use the best practice strategies documented in this article to optimize your script and avoid the error. +If you get `RequestPayloadSizeLimitExceeded`, apply the following strategies to reduce size before you split operations. ### Strategy 1: Move unchanged values out of loops -Limit the number of processes that occur within loops to improve performance. In the following code sample, `context.workbook.worksheets.getActiveWorksheet()` can be moved out of the `for` loop, because it doesn't change within that loop. +Limit the processes inside loops to improve performance. In the following code sample, `context.workbook.worksheets.getActiveWorksheet()` can be moved out of the `for` loop because it doesn't change within that loop. ```js // DO NOT USE THIS CODE SAMPLE. This sample shows a poor performance strategy. @@ -136,7 +153,7 @@ async function run() { } ``` -The following code sample shows logic similar to the preceding code sample, but with an improved performance strategy. The value `context.workbook.worksheets.getActiveWorksheet()` is retrieved before the `for` loop, because this value doesn't need to be retrieved each time the `for` loop runs. Only values that change within the context of a loop should be retrieved within that loop. +The following code sample shows similar logic but with an improved strategy. The value `context.workbook.worksheets.getActiveWorksheet()` is retrieved before the loop because it doesn't change. Only values that vary should be retrieved inside the loop. ```js // This code sample shows a good performance strategy. @@ -157,14 +174,14 @@ async function run() { ### Strategy 2: Create fewer range objects -Create fewer range objects to improve performance and minimize payload size. Two approaches for creating fewer range objects are described in the following article sections and code samples. +Create fewer range objects to improve performance and reduce payload size. Two approaches follow. #### Split each range array into multiple arrays One way to create fewer range objects is to split each range array into multiple arrays, and then process each new array with a loop and a new `context.sync()` call. > [!IMPORTANT] -> Only use this strategy if you've first determined that you're exceeding the payload request size limit. Using multiple loops can reduce the size of each payload request to avoid exceeding the 5MB limit, but using multiple loops and multiple `context.sync()` calls also negatively impacts performance. +> Only use this strategy after you have confirmed that you exceed the payload size limit. Multiple loops reduce the size of each payload request but also add extra `context.sync()` calls and can hurt performance. The following code sample attempts to process a large array of ranges in a single loop and then a single `context.sync()` call. Processing too many range values in one `context.sync()` call causes the payload request size to exceed the 5MB limit. @@ -239,9 +256,14 @@ async function run() { } ``` +## Next steps + +- Review [resource limits and performance optimization](../concepts/resource-limits-and-performance-optimization.md) for host-level constraints. +- Explore [working with multiple ranges](excel-add-ins-multiple-ranges.md) to create fewer objects. +- Add telemetry for data such as operation durations and row counts to guide further performance optimization. + ## See also -* [Excel JavaScript object model in Office Add-ins](excel-add-ins-core-concepts.md) -* [Error handling with the application-specific JavaScript APIs](../testing/application-specific-api-error-handling.md) -* [Resource limits and performance optimization for Office Add-ins](../concepts/resource-limits-and-performance-optimization.md) -* [Worksheet Functions Object (JavaScript API for Excel)](/javascript/api/excel/excel.functions) +- [Excel JavaScript object model in Office Add-ins](excel-add-ins-core-concepts.md) +- [Error handling with the application-specific JavaScript APIs](../testing/application-specific-api-error-handling.md) +- [Worksheet Functions Object (JavaScript API for Excel)](/javascript/api/excel/excel.functions) \ No newline at end of file