This sample shows how to resolve and reopen comment threads.
-
-
-
Setup
-
-
-
-
Try it out
-
To better view the comment changes, open the Comments pane by selecting Show Comments from the Review tab.
-
-
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml b/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml
deleted file mode 100644
index 07bcbf4c2..000000000
--- a/samples/excel/14-conditional-formatting/conditional-formatting-advanced.yaml
+++ /dev/null
@@ -1,238 +0,0 @@
-order: 2
-id: excel-range-conditional-formatting-advanced
-name: Advanced conditional formatting
-description: Applies more than one conditional format on the same range.
-host: EXCEL
-api_set:
- ExcelApi: '1.6'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#apply-conditional-formats-default-priority").click(() => tryCatch(applyConditionalFormatsWithDefaultPriority));
- $("#apply-conditional-formats-explicit-priority").click(() => tryCatch(applyPrioritizedConditionalFormats));
- $("#apply-conditional-formats-stop-if-true").click(() => tryCatch(applyPrioritizedConditionalFormatsWithStopOnTrue));
- $("#remove-conditional-format").click(() => tryCatch(removeConditionalFormat));
-
-
- async function applyConditionalFormatsWithDefaultPriority() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- queueCommandsToClearAllConditionalFormats(sheet);
-
- const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange();
-
- /* When the priority property of ConditionalFormat objects
- is not explicitly set, they are prioritized in the order
- that they are added, with zero-based numbering: 0, 1, ...
- Contradictions are resolved in favor of the format with
- the lower priority number. In the example below, negative
- numbers will get a green background, but NOT a blue font,
- because priority goes to the format that gives them a red font.
- */
-
- // Set low numbers to bold, dark red font. This format will
- // get priority 0.
- const presetFormat = temperatureDataRange.conditionalFormats
- .add(Excel.ConditionalFormatType.presetCriteria);
- presetFormat.preset.format.font.color = "red";
- presetFormat.preset.format.font.bold = true;
- presetFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage };
-
- // Set negative numbers to blue font with green background.
- // This format will get priority 1.
- const cellValueFormat = temperatureDataRange.conditionalFormats
- .add(Excel.ConditionalFormatType.cellValue);
- cellValueFormat.cellValue.format.font.color = "blue";
- cellValueFormat.cellValue.format.fill.color = "lightgreen";
- cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" };
-
- await context.sync();
- });
- }
-
- async function applyPrioritizedConditionalFormats() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- queueCommandsToClearAllConditionalFormats(sheet);
-
- const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange();
-
- /* Contradictions are resolved in favor of the format with
- the lower priority number. In the example below, negative
- numbers will get a bold font, but NOT a red font, because
- priority goes to the format that gives them a blue font.
- */
-
- // Set low numbers to bold, dark red font and assign priority 1.
- const presetFormat = temperatureDataRange.conditionalFormats
- .add(Excel.ConditionalFormatType.presetCriteria);
- presetFormat.preset.format.font.color = "red";
- presetFormat.preset.format.font.bold = true;
- presetFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage };
- presetFormat.priority = 1;
-
- // Set negative numbers to blue font with green background and
- // set priority 0.
- const cellValueFormat = temperatureDataRange.conditionalFormats
- .add(Excel.ConditionalFormatType.cellValue);
- cellValueFormat.cellValue.format.font.color = "blue";
- cellValueFormat.cellValue.format.fill.color = "lightgreen";
- cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" };
- cellValueFormat.priority = 0;
-
- await context.sync();
- });
- }
-
- async function applyPrioritizedConditionalFormatsWithStopOnTrue() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- queueCommandsToClearAllConditionalFormats(sheet);
-
- const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange();
-
- /* Contradictions are resolved in favor of the format with
- the lower priority number. In the example below, negative
- numbers will get a blue font, but NOT a red font, because
- priority goes to the format that gives them a blue font.
- And the font will not be bolded because setting stopIfTrue
- to true on the conditional format with priority 0 blocks
- all formatting for any conditional formats with a higher
- priority value.
- */
-
- // Set low numbers to bold, dark red font and assign priority 1.
- const presetFormat = temperatureDataRange.conditionalFormats
- .add(Excel.ConditionalFormatType.presetCriteria);
- presetFormat.preset.format.font.color = "red";
- presetFormat.preset.format.font.bold = true;
- presetFormat.preset.rule = { criterion: Excel.ConditionalFormatPresetCriterion.oneStdDevBelowAverage };
- presetFormat.priority = 1;
-
- // Set negative numbers to blue font with green background and
- // set priority 0, but set stopIfTrue to true, so none of the
- // formatting of the conditional format with the higher priority
- // value will apply, not even the bolding of the font.
- const cellValueFormat = temperatureDataRange.conditionalFormats
- .add(Excel.ConditionalFormatType.cellValue);
- cellValueFormat.cellValue.format.font.color = "blue";
- cellValueFormat.cellValue.format.fill.color = "lightgreen";
- cellValueFormat.cellValue.rule = { formula1: "=0", operator: "LessThan" };
- cellValueFormat.priority = 0;
- cellValueFormat.stopIfTrue = true;
-
- await context.sync();
- });
- }
-
- async function removeConditionalFormat() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const temperatureDataRange = sheet.tables.getItem("TemperatureTable").getDataBodyRange();
- temperatureDataRange.conditionalFormats.getItemAt(0).delete();
-
- await context.sync();
- });
- }
-
- function queueCommandsToClearAllConditionalFormats(sheet: Excel.Worksheet) {
- const range = sheet.getRange();
- range.conditionalFormats.clearAll();
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- queueCommandsToCreateTemperatureTable(sheet);
- sheet.activate();
-
- await context.sync();
- });
- }
-
- function queueCommandsToCreateTemperatureTable(sheet: Excel.Worksheet) {
- let temperatureTable = sheet.tables.add('A1:M1', true);
- temperatureTable.name = "TemperatureTable";
- temperatureTable.getHeaderRowRange().values = [["Category", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]];
- temperatureTable.rows.add(null, [
- ["Avg High", 40, 38, 44, 45, 51, 56, 67, 72, 79, 59, 45, 41],
- ["Avg Low", 34, 33, 38, 41, 45, 48, 51, 55, 54, 45, 41, 38],
- ["Record High", 61, 69, 79, 83, 95, 97, 100, 101, 94, 87, 72, 66],
- ["Record Low", -1, 2, 9, 24, 28, 32, 36, 39, 35, 21, 12, 4]
- ]);
- temperatureTable.getRange().format.autofitColumns();
- temperatureTable.getRange().format.autofitRows();
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |
-
-
This sample shows how to use priorities to work with conditional formatting of ranges when more than one conditional format
- applies to some cells.
This sample shows how to apply conditional formatting to ranges.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml b/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml
deleted file mode 100644
index 906c96685..000000000
--- a/samples/excel/18-custom-xml-parts/create-set-get-and-delete-custom-xml-parts.yaml
+++ /dev/null
@@ -1,159 +0,0 @@
-order: 1
-id: excel-custom-xml-parts-create-set-get-and-delete-custom-xml-parts
-name: Using custom XML parts
-description: 'Creates, sets, gets, and deletes a custom XML part.'
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.5'
-script:
- content: |
- $("#create-custom-xml-part").click(() => tryCatch(createCustomXmlPart));
- $("#change-custom-xml-part").click(() => tryCatch(changeCustomXmlPart));
- $("#delete-custom-xml-part").click(() => tryCatch(deleteCustomXmlPart));
-
- async function createCustomXmlPart() {
- await Excel.run(async (context) => {
- // You must have the xmlns attribute to populate the
- // CustomXml.namespaceUri property.
- const originalXml = "JuanHongSally";
- const customXmlPart = context.workbook.customXmlParts.add(originalXml);
- customXmlPart.load("id");
- const xmlBlob = customXmlPart.getXml();
-
- await context.sync();
-
- const readableXml = addLineBreaksToXML(xmlBlob.value);
- $("#display-xml").text(readableXml);
-
- // Store the XML part's ID in a setting.
- const settings = context.workbook.settings;
- settings.add("ContosoReviewXmlPartId", customXmlPart.id);
-
- await context.sync();
- });
- }
-
- async function changeCustomXmlPart() {
- await Excel.run(async (context) => {
- const settings = context.workbook.settings;
- const xmlPartIDSetting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value");
- await context.sync();
-
- if (xmlPartIDSetting.value) {
- const customXmlPart = context.workbook.customXmlParts.getItem(xmlPartIDSetting.value);
-
- // The setXml method does a whole-for-whole replacement
- // of the entire XML.
- customXmlPart.setXml("JohnHitomi");
- const xmlBlob = customXmlPart.getXml();
- await context.sync();
-
- const readableXml = addLineBreaksToXML(xmlBlob.value);
- $("#display-xml").text(readableXml);
- await context.sync();
- }
- });
- }
-
- async function deleteCustomXmlPart() {
- await Excel.run(async (context) => {
- const settings = context.workbook.settings;
- const xmlPartIDSetting = settings.getItemOrNullObject("ContosoReviewXmlPartId").load("value");
- await context.sync();
-
- if (xmlPartIDSetting.value) {
- let customXmlPart = context.workbook.customXmlParts.getItem(xmlPartIDSetting.value);
- const xmlBlob = customXmlPart.getXml();
- customXmlPart.delete();
- customXmlPart = context.workbook.customXmlParts.getItemOrNullObject(xmlPartIDSetting.value);
-
- await context.sync();
-
- if (customXmlPart.isNullObject) {
- $("#display-xml").text(`The XML part with the id ${xmlPartIDSetting.value} has been deleted.`);
-
- // Delete the unneeded setting too.
- xmlPartIDSetting.delete();
- } else {
- const readableXml = addLineBreaksToXML(xmlBlob.value);
- const strangeMessage = `This is strange. The XML part with the id ${xmlPartIDSetting.value} has not been deleted:\n${readableXml}`
- $("#display-xml").text(strangeMessage);
- }
-
- await context.sync();
- }
- });
- }
-
- function addLineBreaksToXML(xmlBlob: string) : string {
- const replaceValue = new RegExp(">");
- return xmlBlob.replace(/> <");
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |+
-
-
This sample shows how to create, set, get, and delete custom XML parts in the file.
-
-
-
-
Try it out
-
Press the button to create and display Contoso's Reviewer metadata.
-
-
Press the button to change the reviewers and display the new XML.
-
-
Press the button to delete the XML part.
-
-
-
-
-
-
XML part display
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml b/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml
deleted file mode 100644
index c42b996bd..000000000
--- a/samples/excel/18-custom-xml-parts/test-xml-for-unique-namespace.yaml
+++ /dev/null
@@ -1,145 +0,0 @@
-order: 2
-id: excel-custom-xml-parts-test-xml-for-unique-namespace
-name: Unique namespaces in custom XML
-description: Tests to see if there is only one XML part for a specified namespace.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.5'
-script:
- content: |
- $("#create-custom-xml-part").click(() => tryCatch(createCustomXmlPart));
- $("#test-for-unique-namespace").click(() => tryCatch(testForUniqueNamespace));
- $("#delete-all-custom-xml-parts").click(() => tryCatch(deleteAllCustomXmlParts));
-
- async function createCustomXmlPart() {
- await Excel.run(async (context) => {
- $("#display-xml").text("");
-
- // You must have the xmlns attribute to populate the
- // CustomXml.namespaceUri property.
- const originalXml = "JuanHongSally";
- const customXmlPart = context.workbook.customXmlParts.add(originalXml);
- const xmlBlob = customXmlPart.getXml();
-
- await context.sync();
-
- // Make it a bit more readable.
- const readableXml = xmlBlob.value.replace(/>\n<");
- $("#display-xml").text(readableXml);
-
- await context.sync();
- });
- }
-
- async function testForUniqueNamespace() {
- await Excel.run(async (context) => {
- $("#display-xml").text("");
- const contosoNamespace = "http://schemas.contoso.com/review/1.0";
- const customXmlParts = context.workbook.customXmlParts;
- const filteredXmlParts = customXmlParts.getByNamespace(contosoNamespace);
- const numberOfPartsInNamespace = filteredXmlParts.getCount();
-
- await context.sync();
-
- if (numberOfPartsInNamespace.value == 1) {
- const onlyXmlPartInNamespace = filteredXmlParts.getOnlyItem();
- const xmlBlob = onlyXmlPartInNamespace.getXml();
-
- await context.sync();
-
- // Make it a bit more readable.
- const readableXml = xmlBlob.value.replace(/>\n<");
-
- $("#display-xml").text(`The only XML part in the namespace ${contosoNamespace} is:
- ${readableXml}`);
-
- } else {
- console.log(`There are ${numberOfPartsInNamespace.value} XML parts with namespace ${contosoNamespace}. There should be exactly 1.`);
- }
-
- await context.sync();
- });
- }
-
- async function deleteAllCustomXmlParts() {
- await Excel.run(async (context) => {
- $("#display-xml").text("");
- const customXmlParts = context.workbook.customXmlParts;
- customXmlParts.load("items");
-
- await context.sync();
-
- for (let i = 0; i < customXmlParts.items.length; i++) {
- customXmlParts.items[i].delete();
- }
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |+
-
-
This sample shows how to determine if there is just one XML part for a specified namespace.
-
-
-
-
Try it out
-
Press the "Create XML part" button to create and display Contoso's Reviewer metadata. Press it more than once if you want to set up an error situation.
-
-
Press the "Test for unique namespace" button to see if there is more than one XML part with the Contoso namespace. If there is more than one, an error is thrown.
-
-
To start over, press "Delete all XML parts".
-
-
-
-
-
XML part display
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/20-data-types/data-types-entity-attribution.yaml b/samples/excel/20-data-types/data-types-entity-attribution.yaml
deleted file mode 100644
index 953eaee8f..000000000
--- a/samples/excel/20-data-types/data-types-entity-attribution.yaml
+++ /dev/null
@@ -1,234 +0,0 @@
-order: 6
-id: excel-data-types-entity-attribution
-name: 'Data types: Entity value attribution properties'
-description: This sample shows how to set data provider attributions on entity values in the card layout.
-host: EXCEL
-api_set:
- ExcelApi: '1.16'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#add-entities-to-table").click(() => tryCatch(addEntitiesToTable));
-
- async function addEntitiesToTable() {
- // This function retrieves data for each of the existing products in the table,
- // creates entity values for each of those products, and adds the entities
- // to the table.
- await Excel.run(async (context) => {
- const productsTable = context.workbook.tables.getItem("ProductsTable");
-
- // Add a new column to the table for the entity values.
- productsTable.columns.getItemOrNullObject("Product").delete();
- const productColumn = productsTable.columns.add(0, null, "Product");
-
- // Get product data from the table.
- const dataRange = productsTable.getDataBodyRange();
- dataRange.load("values");
-
- await context.sync();
-
- // Set up the entities by mapping the product names to
- // the sample JSON product data.
- const entities = dataRange.values.map((rowValues) => {
- // Get products and product properties.
- const product = getProduct(rowValues[1]);
-
- // Create entities by combining Products Table data and JSON data.
- return [makeProductEntity(rowValues[1], rowValues[2], product)];
- });
-
- // Add the complete entities to the Products Table.
- productColumn.getDataBodyRange().valuesAsJson = entities;
-
- productColumn.getRange().format.autofitColumns();
- await context.sync();
- });
- }
-
- // Create entities with card layout and data provider fields.
- function makeProductEntity(productID: number, productName: string, product?: any) {
- const entity: Excel.EntityCellValue = {
- type: Excel.CellValueType.entity,
- text: productName,
- properties: {
- "Product ID": {
- type: Excel.CellValueType.string,
- basicValue: productID.toString() || ""
- },
- "Product Name": {
- type: Excel.CellValueType.string,
- basicValue: productName || ""
- },
- "Quantity Per Unit": {
- type: Excel.CellValueType.string,
- basicValue: product.quantityPerUnit || ""
- },
- // Add Unit Price as a formatted number.
- "Unit Price": {
- type: Excel.CellValueType.formattedNumber,
- basicValue: product.unitPrice,
- numberFormat: "$* #,##0.00"
- }
- },
- layouts: {
- card: {
- title: { property: "Product Name" },
- sections: [
- {
- layout: "List",
- properties: ["Product ID"]
- },
- {
- layout: "List",
- title: "Quantity and price",
- collapsible: true,
- collapsed: false,
- properties: ["Quantity Per Unit", "Unit Price"]
- }
- ]
- }
- },
- provider: {
- description: product.providerName, // Name of the data provider. Displays as a tooltip when hovering over the logo. Also displays as a fallback if the source address for the image is broken.
- logoSourceAddress: product.sourceAddress, // Source URL of the logo to display.
- logoTargetAddress: product.targetAddress // Destination URL that the logo navigates to when clicked.
- }
- };
-
- return entity;
- }
-
- // Get products and product properties.
- function getProduct(productID: number): any {
- return products.find((p) => p.productID == productID);
- }
-
- /** Set up Sample worksheet. */
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const productsTable = sheet.tables.add("A1:C1", true /*hasHeaders*/);
- productsTable.name = "ProductsTable";
-
- productsTable.getHeaderRowRange().values = [["Product", "ProductID", "ProductName"]];
-
- productsTable.rows.add(
- null /*add at the end*/,
- products.map((p) => [null, p.productID, p.productName])
- );
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
- /** Sample JSON product data. */
- const products = [
- {
- productID: 1,
- productName: "Chai",
- quantityPerUnit: "10 boxes x 20 bags",
- unitPrice: 18,
- providerName: "Microsoft",
- sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/microsoft-logo.png?raw=true",
- targetAddress: "http://microsoft.com/"
- },
- {
- productID: 2,
- productName: "Chang",
- quantityPerUnit: "24 - 12 oz bottles",
- unitPrice: 19,
- providerName: "MSN",
- sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/msn-logo.png?raw=true",
- targetAddress: "http://msn.com/"
- },
- {
- productID: 3,
- productName: "Aniseed Syrup",
- quantityPerUnit: "12 - 550 ml bottles",
- unitPrice: 10,
- providerName: "Xbox",
- sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/xbox-logo.png?raw=true",
- targetAddress: "http://xbox.com/"
- },
- {
- productID: 4,
- productName: "Chef Anton's Cajun Seasoning",
- quantityPerUnit: "48 - 6 oz jars",
- unitPrice: 22,
- providerName: "Microsoft",
- sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/microsoft-logo.png?raw=true",
- targetAddress: "http://microsoft.com/"
- },
- {
- productID: 5,
- productName: "Chef Anton's Gumbo Mix",
- quantityPerUnit: "36 boxes",
- unitPrice: 21.35,
- providerName: "MSN",
- sourceAddress: "https://github.com/OfficeDev/office-js-snippets/blob/main/.github/images/msn-logo.png?raw=true",
- targetAddress: "http://msn.com/"
- },
- ];
- language: typescript
-template:
- content: |-
-
-
This sample shows how to set data provider attributions on entity values in the card layout. The data is aggregated from three different data providers, and three attributions are displayed.
-
-
-
Set up
-
-
-
-
Try it out
-
-
To see the entity value's data attribution, click the icon to the left of the title in the Product column after selecting Add entity values.
-
The data attribution appears as a logo in the bottom left corner of the entity card. Hover over the logo to see the name of the data provider. Click on the logo to visit the data provider's URL.
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/20-data-types/data-types-entity-icons.yaml b/samples/excel/20-data-types/data-types-entity-icons.yaml
deleted file mode 100644
index 335f1e75d..000000000
--- a/samples/excel/20-data-types/data-types-entity-icons.yaml
+++ /dev/null
@@ -1,120 +0,0 @@
-order: 5
-id: excel-data-types-icons
-name: 'Data types: Create entity icons'
-description: Display all the icons available for entity data types.
-host: EXCEL
-api_set:
- ExcelApi: '1.16'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#create-icons").click(() => tryCatch(createIcons));
-
- // Retrieve the entity card icons enum.
- const iconNames = Excel.EntityCompactLayoutIcons;
- let icons;
-
- function createEntitiesWithIcons(icons): Excel.EntityCellValue[][] {
- /* This method creates an entity data type for each
- * icon in the `EntityCompactLayoutIcons` enum,
- * and then displays the icon name with its icon.
- */
- let entities = [];
- icons.forEach(function(iconName, index, array) {
- let icon = iconNames[iconName];
- entities.push([
- {
- type: "Entity",
- text: iconName,
- properties: {},
- layouts: {
- compact: {
- icon
- }
- }
- }
- ]);
- });
- return entities;
- }
-
- async function createIcons() {
- await Excel.run(async (context) => {
- /* This method populates Column A in the worksheet
- * with all of the entities and icons created by the
- * `createEntitiesWithIcons` method.
- */
- const sheet = context.workbook.worksheets.getItemOrNullObject("Sample");
- const rangeString = "A1:A" + Object.keys(iconNames).length;
- const range = sheet.getRange(rangeString );
-
- range.valuesAsJson = createEntitiesWithIcons(Object.keys(iconNames));
-
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create a new worksheet called "Sample" and activate it.
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to display all the icons available for entity data types, along with the name of each icon.
-
After creating the icons, select an icon to open the entity card for that data type. The entity cards in this sample display only the icon names.
This sample shows how to create entity values for each row in a table. An entity value is a container for data types, similar to an object in object-oriented programming.
-
In particular, this sample highlights the card layout options of an entity value, including the title, an image, collapsible sections, and nested entity values.
-
-
-
Set up
-
-
-
-
Try it out
-
-
To see the entity value, click the icon to the left of the title in the Product column after selecting Add entity values.
-
Note: In Excel on Mac, nested icons (such as the icons that display inside an entity card) always display as the default icon, even when another icon is selected with the API. This is a known bug.
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/20-data-types/data-types-error-values.yaml b/samples/excel/20-data-types/data-types-error-values.yaml
deleted file mode 100644
index 898a52073..000000000
--- a/samples/excel/20-data-types/data-types-error-values.yaml
+++ /dev/null
@@ -1,93 +0,0 @@
-order: 4
-id: excel-data-types-error-values
-name: 'Data types: Set error values'
-description: This sample shows how to set a cell value to an error data type.
-host: EXCEL
-api_set:
- ExcelApi: '1.16'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#setBusyError").click(() => tryCatch(setBusyError));
-
- async function setBusyError() {
- // This function sets the value of cell A1 to a #BUSY! error using data types.
- await Excel.run(async (context) => {
- // Retrieve the Sample worksheet and cell A1 on that sheet.
- const sheet = context.workbook.worksheets.getItemOrNullObject("Sample");
- const range = sheet.getRange("A1");
-
- // Get the error data type and set its type to `busy`.
- const error: Excel.ErrorCellValue = {
- type: Excel.CellValueType.error,
- errorType: Excel.ErrorCellValueType.busy
- };
-
- // Set cell A1 as the busy error.
- range.valuesAsJson = [[error]];
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create a new worksheet called "Sample" and activate it.
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to set the value of cell A1 to the #BUSY! error data type.
-
-
-
Set up
-
-
Try it out
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/20-data-types/data-types-formatted-number.yaml b/samples/excel/20-data-types/data-types-formatted-number.yaml
deleted file mode 100644
index e534b3226..000000000
--- a/samples/excel/20-data-types/data-types-formatted-number.yaml
+++ /dev/null
@@ -1,157 +0,0 @@
-order: 1
-id: excel-data-types-formatted-number
-name: 'Data types: Formatted numbers'
-description: This sample shows how to set and get data types using the formatted number properties.
-host: EXCEL
-api_set:
- ExcelApi: '1.16'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#set-formatted-number-date").click(() => tryCatch(setFormattedNumberDate));
- $("#set-formatted-number-currency").click(() => tryCatch(setFormattedNumberCurrency));
- $("#get-formatted-number").click(() => tryCatch(getFormattedNumber));
-
- async function setFormattedNumberDate() {
- // This function creates a formatted number data type,
- // and sets the format of this data type as a date.
- await Excel.run(async (context) => {
- // Get the Sample worksheet and a range on that sheet.
- const sheet = context.workbook.worksheets.getItemOrNullObject("Sample");
- const dateRange = sheet.getRange("A1");
-
- // Write a number formatted as a date to cell A1.
- dateRange.valuesAsJson = [
- [
- {
- type: Excel.CellValueType.formattedNumber,
- basicValue: 32889.0,
- numberFormat: "m/d/yyyy"
- }
- ]
- ];
- await context.sync();
- });
- }
-
- async function setFormattedNumberCurrency() {
- // This function creates a formatted number data type,
- // and sets the format of this data type as a currency.
- await Excel.run(async (context) => {
- // Get the Sample worksheet and a range on that sheet.
- const sheet = context.workbook.worksheets.getItemOrNullObject("Sample");
- const currencyRange = sheet.getRange("A2");
-
- // Write a number formatted as currency to cell A2.
- currencyRange.valuesAsJson = [
- [
- {
- type: Excel.CellValueType.formattedNumber,
- basicValue: 12.34,
- numberFormat: "$* #,##0.00"
- }
- ]
- ];
-
- await context.sync();
- });
- }
-
- async function getFormattedNumber() {
- // This function prints information about data types
- // in cells A1 and A2 to the console.
- await Excel.run(async (context) => {
- // Get the Sample worksheet and two ranges on that sheet.
- const sheet = context.workbook.worksheets.getItemOrNullObject("Sample");
- const currencyRange = sheet.getRange("A2");
- const dateRange = sheet.getRange("A1");
-
- // Load the data type property of the ranges.
- currencyRange.load("valuesAsJson");
- dateRange.load("valuesAsJson");
- await context.sync();
-
- const currencyValues = currencyRange.valuesAsJson[0][0];
- const dateValues = dateRange.valuesAsJson[0][0];
-
- // Print information about the data types to the console.
- console.log("Date");
- console.log(" Type: " + dateValues.type);
- console.log(" Basic value: " + dateValues.basicValue);
- console.log(" Basic type: " + dateValues.basicType);
- console.log(" Number format: " + (dateValues as Excel.FormattedNumberCellValue).numberFormat);
-
- console.log("Currency");
- console.log(" Type: " + currencyValues.type);
- console.log(" Basic value: " + currencyValues.basicValue);
- console.log(" Basic type: " + currencyValues.basicType);
- console.log(" Number format: " + (currencyValues as Excel.FormattedNumberCellValue).numberFormat);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create a new worksheet called "Sample" and activate it.
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */ async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to work with the formatted number data type.
-
-
-
Set up
-
-
Try it out
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/20-data-types/data-types-references.yaml b/samples/excel/20-data-types/data-types-references.yaml
deleted file mode 100644
index af9070c87..000000000
--- a/samples/excel/20-data-types/data-types-references.yaml
+++ /dev/null
@@ -1,345 +0,0 @@
-order: 7
-id: excel-data-types-references
-name: 'Data types: Entity values with references'
-description: 'This sample shows how to create entity values with references to other entity values. An entity value is a container for data, and this container can reference (or contain) other entities within the original entity. One entity can contain multiple additional entities.'
-host: EXCEL
-api_set:
- ExcelApi: '1.16'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#add-entities-to-table").click(() => tryCatch(addEntitiesToTable));
-
- async function addEntitiesToTable() {
- // This function creates entity values with references to other entity values.
- // It retrieves data for each of the employees in the table on the worksheet,
- // creates entity values for each of those employees, and adds the entities
- // to the table. Each employee entity references (or contains) other
- // employee entities. In this scenario, the purpose of one employee
- // referencing another is to show a managerial hierarchy.
- await Excel.run(async (context) => {
- const employeesTable = context.workbook.tables.getItem("EmployeesTable");
-
- // Refresh the table column with the entity values.
- employeesTable.columns.getItemOrNullObject("Employee").delete();
- const employeeColumn = employeesTable.columns.add(0, null, "Employee");
-
- // Get employee data from the table.
- const dataRange = employeesTable.getDataBodyRange();
- dataRange.load("values");
- await context.sync();
-
- // Create the entities by mapping the employee IDs in table to the sample
- // JSON employee data.
- const entities = dataRange.values.map((rowValues) => {
- // Get employee properties.
- const employee = getEmployee(rowValues[1] /* Employee ID */);
-
- // Collect all the references that are needed to make the employee entity.
- const references = collectReferences(employee);
-
- // Create employee entity from employee properties.
- const employeeEntity = makeEmployeeEntity(
- rowValues[2], /* Last name */
- rowValues[3], /* First name */
- employee,
- references
- );
-
- // Collect reference values for the employee entity.
- const referencedValues: any[] = [{ type: "Root" }];
- references.slice(1).forEach((id) => {
- const referencedEmployee = getEmployee(id);
- referencedValues.push(
- makeEmployeeEntity(referencedEmployee.lastName, referencedEmployee.firstName, referencedEmployee, references)
- );
- });
- employeeEntity.referencedValues = referencedValues;
-
- return [employeeEntity];
- });
-
- // Add the complete entities to the Employees Table.
- employeeColumn.getDataBodyRange().valuesAsJson = entities;
- employeeColumn.getRange().format.autofitColumns();
- await context.sync();
- });
- }
-
- // Helper function to collect all the references for the employee entity.
- // A reference means one entity contains another entity.
- function collectReferences(employee) {
- const references: number[] = [];
- collectManagerReferences(employee, references);
- return references;
- }
-
- // Helper function to collect manager and direct report references for each employee entity.
- function collectManagerReferences(employee, references: number[]) {
- // Confirm references haven't already been collected for this employee.
- if (references.indexOf(employee.employeeID) >= 0) {
- return;
- }
-
- // Record the reference for the employee.
- ensureReferenceExist(references, employee.employeeID);
-
- // Record the reference for the manager, if the employee has a manager.
- if (employee.reportsTo != null) {
- // Get the manager.
- const manager = getEmployee(employee.reportsTo);
- // Collect references for the manager.
- collectManagerReferences(manager, references);
- }
-
- // Collect references for each of the direct reports of the employee, if any.
- const directReports = employee.directReports || getDirectReports(employee.employeeID);
- if (directReports.length > 0) {
- directReports.forEach((direct) => collectManagerReferences(direct, references));
- }
- }
-
- // Helper function to check whether a specific reference ID exists in a list of IDs.
- // If the ID doesn't exist, add it to the list.
- function ensureReferenceExist(list: number[], id: number) {
- if (list.indexOf(id) < 0) {
- list.push(id);
- }
- }
-
- // Create entities from employee properties.
- function makeEmployeeEntity(lastName: string, firstName: string, employee: any, references: number[]): Excel.EntityCellValue {
- const entity: Excel.EntityCellValue = {
- type: Excel.CellValueType.entity,
- text: `${firstName} ${lastName}`,
- properties: {
- "Employee ID": {
- type: Excel.CellValueType.string,
- basicValue: employee.employeeID.toString()
- },
- "Last Name": {
- type: Excel.CellValueType.string,
- basicValue: lastName
- },
- "First Name": {
- type: Excel.CellValueType.string,
- basicValue: firstName
- },
- Name: {
- type: Excel.CellValueType.string,
- basicValue: `${firstName} ${lastName}`
- },
- Title: {
- type: Excel.CellValueType.string,
- basicValue: employee.title
- }
- },
- layouts: {
- card: {
- title: { property: "Name" },
- sections: [
- {
- layout: "List",
- properties: ["Employee ID", "First Name", "Last Name", "Title"]
- }
- ]
- }
- }
- };
-
- // Add manager reference, if the employee has a manager.
- if (employee.reportsTo != null) {
- entity.properties["Manager"] = {
- type: "Reference",
- reference: references.indexOf(employee.reportsTo)
- };
- entity.layouts.card.sections[0].properties.push("Manager");
- }
-
- // Add references for direct reports, if any.
- if (employee.directReports.length > 0) {
- entity.properties["Direct Reports"] = {
- type: Excel.CellValueType.array,
- elements: employee.directReports.map((direct) => {
- return [
- {
- type: "Reference",
- reference: references.indexOf(direct.employeeID)
- }
- ];
- }),
- };
- entity.layouts.card.sections[0].properties.push("Direct Reports");
- }
-
- return entity;
- }
-
- // Get employee properties.
- function getEmployee(employeeID: number): any {
- // Find the employee in the sample data.
- const employee = employees.find((e) => e.employeeID === employeeID);
-
- // Add direct reports for the employee.
- employee["directReports"] = getDirectReports(employeeID);
- return employee;
- }
-
- // Get direct reports of employee.
- function getDirectReports(employeeID: number): any {
- return employees.filter((e) => e.reportsTo === employeeID);
- }
-
- /** Set up Sample worksheet with a table of employee data. */
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const employeesTable = sheet.tables.add("A1:D1", true /* hasHeaders */);
- employeesTable.name = "EmployeesTable";
-
- employeesTable.getHeaderRowRange().values = [["Employee", "EmployeeID", "LastName", "FirstName"]];
-
- employeesTable.rows.add(
- null /* Add at the end. */,
- employees.map((e) => [null, e.employeeID, e.lastName, e.firstName])
- );
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
- /** Sample JSON employee data. */
- const employees = [
- {
- employeeID: 1,
- lastName: "Davolio",
- firstName: "Nancy",
- title: "Vice President, Sales",
- reportsTo: null
- },
- {
- employeeID: 2,
- lastName: "Fuller",
- firstName: "Andrew",
- title: "Sales Representative",
- reportsTo: 1
- },
- {
- employeeID: 3,
- lastName: "Leverling",
- firstName: "Janet",
- title: "Sales Representative",
- reportsTo: 4
- },
- {
- employeeID: 4,
- lastName: "Peacock",
- firstName: "Margaret",
- title: "Sales Manager",
- reportsTo: 1
- },
- {
- employeeID: 5,
- lastName: "Buchanan",
- firstName: "Steven",
- title: "Sales Representative",
- reportsTo: 4
- },
- {
- employeeID: 6,
- lastName: "Suyama",
- firstName: "Michael",
- title: "Sales Representative",
- reportsTo: 4
- },
- {
- employeeID: 7,
- lastName: "King",
- firstName: "Robert",
- title: "Sales Representative",
- reportsTo: 4
- },
- {
- employeeID: 8,
- lastName: "Callahan",
- firstName: "Laura",
- title: "Inside Sales Coordinator",
- reportsTo: 1
- },
- {
- employeeID: 9,
- lastName: "Dodsworth",
- firstName: "Anne",
- title: "Sales Representative",
- reportsTo: 4
- }
- ];
- language: typescript
-template:
- content: |
-
-
This sample shows how to create entity values with references to other entity values. An entity value is a container for data, and this container can reference (or contain) other entities within the original entity. One entity can contain multiple additional entities.
-
-
-
Set up
-
-
-
-
Try it out
-
To see referenced entities within an entity, take the following steps.
-
-
Select Add entity values to add entity values to the table.
-
-
Open the Andrew Fuller entity card by selecting the icon to the left of this name in the Employee column.
-
In the Andrew Fuller entity card, select the Manager field. This opens the referenced entity for Nancy Davolio.
-
The referenced Nancy Davolio entity itself contains multiple referenced entities in the Direct Reports field. Select the Direct Reports field to explore the referenced entities for all the employees that report to Nancy Davolio.
-
To navigate back to the original Andrew Fuller entity, select the Back arrow in the top left corner of the entity card.
-
-
You can also use the Extract to grid button in the card modal window, to the right of the Manager or Direct Reports fields, to add the referenced entities to the table in new columns.
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/20-data-types/data-types-web-image.yaml b/samples/excel/20-data-types/data-types-web-image.yaml
deleted file mode 100644
index 5cdf97001..000000000
--- a/samples/excel/20-data-types/data-types-web-image.yaml
+++ /dev/null
@@ -1,200 +0,0 @@
-order: 2
-id: excel-data-types-web-image
-name: 'Data types: Web images'
-description: This sample shows how to set and get web images in a worksheet using data types.
-host: EXCEL
-api_set:
- ExcelApi: '1.16'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#insert-image").click(() => tryCatch(insertImage));
- $("#retrieve-image-info").click(() => tryCatch(retrieveImageInfo));
- $("#open-image").click(() => tryCatch(openImage));
- $("#clear-form").click(() => tryCatch(clearForm));
-
- async function insertImage() {
- // This function inserts a web image into the currently selected cell.
- await Excel.run(async (context) => {
- // Retrieve image data from the task pane and then clear the input fields.
- const imageUrl = $("#url").val() as string;
- const imageAltText = $("#alt-text").val() as string;
- clearForm();
-
- // Load the active cell.
- const activeCell = context.workbook.getActiveCell();
- activeCell.load();
- await context.sync();
-
- if (!imageUrl) {
- console.log("Please enter an image URL.");
- return;
- }
-
- // Create a web image object and assign the image details.
- const webImage: Excel.WebImageCellValue = {
- type: "WebImage", /* The string equivalent of `Excel.CellValueType.webImage`. */
- address: imageUrl,
- altText: imageAltText
- };
-
- // Insert web image into the active cell.
- activeCell.valuesAsJson = [[webImage]];
-
- await context.sync();
- });
- }
-
- async function retrieveImageInfo() {
- // This function retrieves image data from a selected cell and displays it in the existing input fields in the task pane.
- await Excel.run(async (context) => {
- // Load the active cell information.
- const activeCell = context.workbook.getActiveCell();
- activeCell.load("valuesAsJson");
- await context.sync();
-
- // Get image data from the active cell.
- const values = activeCell.valuesAsJson;
- const webImageData = values[0][0] as Excel.WebImageCellValue;
- const webImageUrl = webImageData.address;
- const webImageAltText = webImageData.altText;
-
- if (!webImageUrl) {
- console.log("The selected cell is missing an image URL. Make sure to select a cell that contains an image.");
- return;
- }
-
- // Assign image data to corresponding input fields in the task pane.
- $("#url").val(webImageUrl);
- $("#alt-text").val(webImageAltText);
- });
- }
-
- async function openImage() {
- // This function retrieves the image URL from the selected cell and opens that image in a new browser tab.
- await Excel.run(async (context) => {
- // Load the active cell information.
- const activeCell = context.workbook.getActiveCell();
- activeCell.load("valuesAsJson");
- await context.sync();
-
- // Get image URL from the active cell.
- const values = activeCell.valuesAsJson;
- const webImageData = values[0][0] as Excel.WebImageCellValue;
- const webImageUrl = webImageData.address;
-
- if (!webImageUrl) {
- console.log("The selected cell is missing an image URL. Select a cell that contains an image.");
- return;
- }
-
- // Open the image URL in a new browser tab.
- const tab = window.open(webImageData.address, "_blank");
- });
- }
-
- async function clearForm() {
- // Clear the input fields in the task pane.
- $("#url").val("");
- $("#alt-text").val("");
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create a new worksheet called "Sample" and activate it.
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to work with the web image data type. Insert an image into the selected cell and then
- retrieve information about that image.
-
-
-
-
Set up
-
Add a new worksheet and then enter the URL and alt text for an image of your choice.
-
-
-
-
-
-
-
-
-
Try it out
-
Select the cell you want to insert the web image into, and then select the Insert image button.
-
-
-
Select the cell containing the web image that you want to view the details of, and then select the Retrieve image details button. The image details will display here in the task pane, in the preceding Image URL and Alt text fields.
-
-
-
Select the cell with the image you want to view and then select the Open image in browser button. The image will open in a new web browser tab.
-
-
-
Clear the Image URL and Alt text fields in the task pane.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
-
- label {
- display: inline-block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
-
- input {
- display: inline-block;
- padding: 5px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/22-data-validation/data-validation.yaml b/samples/excel/22-data-validation/data-validation.yaml
deleted file mode 100644
index cabcc1092..000000000
--- a/samples/excel/22-data-validation/data-validation.yaml
+++ /dev/null
@@ -1,192 +0,0 @@
-order: 1
-id: excel-data-validation
-name: Data validation
-description: 'Sets data validation rules on ranges, prompts users to enter valid data, and displays messages when invalid data is entered.'
-host: EXCEL
-api_set:
- ExcelApi: '1.8'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#positive-number").click(() => tryCatch(addPositiveNumberRequirement));
- $("#require-approved-location").click(() => tryCatch(requireApprovedName));
- $("#comment-redundancy").click(() => tryCatch(warnAboutCommentRedundancy));
-
- async function addPositiveNumberRequirement() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Decision");
- const rankingRange = sheet.tables.getItem("NameOptionsTable").columns.getItem("Ranking").getDataBodyRange();
-
- // When you are developing, it is a good practice to
- // clear the dataValidation object with each run of your code.
- rankingRange.dataValidation.clear();
-
- let greaterThanZeroRule = {
- wholeNumber: {
- formula1: 0,
- operator: Excel.DataValidationOperator.greaterThan
- }
- };
- rankingRange.dataValidation.rule = greaterThanZeroRule;
-
- rankingRange.dataValidation.prompt = {
- message: "Please enter a positive number.",
- showPrompt: true,
- title: "Positive numbers only."
- };
-
- rankingRange.dataValidation.errorAlert = {
- message: "Sorry, only positive numbers are allowed",
- showAlert: true,
- style: "Stop",
- title: "Negative Number Entered"
- };
-
- await context.sync();
- });
- }
-
- async function requireApprovedName() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Decision");
- const nameRange =
- sheet.tables.getItem("NameOptionsTable").columns.getItem("Baby Name").getDataBodyRange();
-
- // When you are developing, it is a good practice to
- // clear the dataValidation object with each run of your code.
- nameRange.dataValidation.clear();
-
- const nameSourceRange = context.workbook.worksheets.getItem("Names").getRange("A1:A3");
-
- let approvedListRule = {
- list: {
- inCellDropDown: true,
- source: nameSourceRange
- }
- };
- nameRange.dataValidation.rule = approvedListRule;
-
- await context.sync();
- });
- }
-
- async function warnAboutCommentRedundancy() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Decision");
- const commentsRange =
- sheet.tables.getItem("NameOptionsTable").columns.getItem("Comments").getDataBodyRange();
-
- // When you are developing, it is a good practice to
- // clear the dataValidation object with each run of your code.
- commentsRange.dataValidation.clear();
-
- // If the value of A2 is contained in the value of C2, then
- // SEARCH(A2,C2) returns the number where it begins. Otherwise,
- // it does not return a number.
- let redundantStringRule = {
- custom: {
- formula: "=NOT(ISNUMBER(SEARCH(A2,C2)))"
- }
- };
- commentsRange.dataValidation.rule = redundantStringRule;
- commentsRange.dataValidation.errorAlert = {
- message: "It is redundant to include the baby name in the comment.",
- showAlert: true,
- style: "Information",
- title: "Baby Name in Comment"
- };
-
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Decision").delete();
- const decisionSheet = context.workbook.worksheets.add("Decision");
-
- const optionsTable = decisionSheet.tables.add("A1:C4", true /*hasHeaders*/);
- optionsTable.name = "NameOptionsTable";
- optionsTable.showBandedRows = false;
-
- optionsTable.getHeaderRowRange().values = [["Baby Name", "Ranking", "Comments"]];
-
- decisionSheet.getUsedRange().format.autofitColumns();
- decisionSheet.getUsedRange().format.autofitRows();
-
- // The names that will be allowed in the Baby Name column are
- // listed in a range on the Names sheet.
- context.workbook.worksheets.getItemOrNullObject("Names").delete();
- const namesSheet = context.workbook.worksheets.add("Names");
-
- namesSheet.getRange("A1:A3").values = [["Sue"], ["Ricky"], ["Liz"]];
- decisionSheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |
-
-
This sample shows how to apply data validation to cells.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
Press Require approved name and then click on a cell in the Baby Name column and use the drop down to enter an approved value.
-
-
Press Require positive numbers and then click on a cell in the Ranking column. Note the prompt. Try to set the value to a negative number and note the error message.
-
-
Press Warn about comment redundancy and then click on a cell in the Comments column and enter a comment that includes the baby name for the same row. Note the informational message that pops up.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/26-document/custom-properties.yaml b/samples/excel/26-document/custom-properties.yaml
deleted file mode 100644
index a18cec122..000000000
--- a/samples/excel/26-document/custom-properties.yaml
+++ /dev/null
@@ -1,141 +0,0 @@
-order: 3
-id: excel-document-custom-properties
-name: Custom properties
-description: Gets and sets custom properties at the document and worksheet levels.
-host: EXCEL
-api_set:
- ExcelAPI: '1.12'
-script:
- content: |
- $("#set-custom-doc-property").click(() => tryCatch(setCustomDocProperty)); $("#get-custom-doc-properties").click(() => tryCatch(getCustomDocProperties)); $("#set-custom-worksheet-property").click(() => tryCatch(setCustomWorksheetProperty)); $("#get-custom-worksheet-properties").click(() => tryCatch(getCustomWorksheetProperties));
-
- /* To learn how to view document properties in the UI,
- * see https://support.office.com/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75
- */
-
- async function setCustomDocProperty() {
- await Excel.run(async (context) => {
- // Get the key/value pair from the task pane.
- const userKey = $("#key").text();
- const userValue = $("#value").text();
-
- // Add the custom property.
- const customDocProperties = context.workbook.properties.custom;
- customDocProperties.add(userKey, userValue);
-
- await context.sync();
-
- console.log(`Successfully set custom document property ${userKey}:${userValue}.`);
- });
- }
-
- async function getCustomDocProperties() {
- await Excel.run(async (context) => {
- // Load the keys and values of all custom properties.
- const customDocProperties = context.workbook.properties.custom;
- customDocProperties.load(["key", "value"]);
- await context.sync();
-
- // Log each custom property to the console.
- // Note that your document may have more properties than those you have set using this snippet.
- customDocProperties.items.forEach((property) => {
- console.log(`${property.key}:${property.value}`);
- });
- });
- }
-
- async function setCustomWorksheetProperty() {
- await Excel.run(async (context) => {
- // Get the key/value pair from the task pane.
- const userKey = $("#key").text();
- const userValue = $("#value").text();
-
- // Add the custom property.
- const customWorksheetProperties = context.workbook.worksheets.getActiveWorksheet().customProperties;
- customWorksheetProperties.add(userKey, userValue);
-
- await context.sync();
-
- console.log(`Successfully set custom worksheet property ${userKey}:${userValue}.`);
- });
- }
-
- async function getCustomWorksheetProperties() {
- await Excel.run(async (context) => {
- // Load the keys and values of all custom properties in the current worksheet.
- const customWorksheetProperties = context.workbook.worksheets.getActiveWorksheet().customProperties;
- customWorksheetProperties.load(["key", "value"]);
- await context.sync();
-
- // Log each custom property to the console.
- // Note that your document may have more properties than those you have set using this snippet.
- customWorksheetProperties.items.forEach((property) => {
- console.log(`${property.key}:${property.value}`);
- });
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to set and get custom properties at both the document level and the worksheet level.
-
-
-
-
Enter the key/value pairs for your custom properties.
-
Key:
-
Value:
-
-
-
-
-
-
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/26-document/get-file-in-slices-async.yaml b/samples/excel/26-document/get-file-in-slices-async.yaml
deleted file mode 100644
index 514a925c5..000000000
--- a/samples/excel/26-document/get-file-in-slices-async.yaml
+++ /dev/null
@@ -1,218 +0,0 @@
-order: 1
-id: excel-document-get-file-in-slices-async
-name: Get file using slicing
-description: Uses slicing to get the byte array and Base64-encoded string that represent the current document.
-host: EXCEL
-api_set:
- ExcelApi: '1.4'
-script:
- content: |-
- $("#setup").click(() => tryCatch(setup));
- $("#get-file").click(() => tryCatch(getCurrentFile));
- $("#new-workbook-from-file").click(() => tryCatch(newWorkbookFromFile));
-
- function getCurrentFile() {
- const sliceSize = 4096; /*Bytes*/
-
- // This snippet specifies a small slice size to show how the getFileAsync() method uses slices.
- Office.context.document.getFileAsync(Office.FileType.Compressed, { sliceSize: sliceSize },
- function (result) {
- if (result.status === Office.AsyncResultStatus.Failed) {
- return onError(result.error);
- }
-
- // Result.value is the File object.
- getFileContents(result.value, onSuccess, onError);
- });
-
- function onError(error: Office.Error): void {
- console.error(error);
- }
-
- function onSuccess(byteArray: number[]) {
- // Now that all of the file content is stored in the "data" parameter,
- // you can do something with it, such as print the file, store the file in a database, etc.
- console.log("Received the full contents of the file.");
-
- let base64string = base64js.fromByteArray(byteArray);
- $('#file-contents').val(base64string).show();
-
- console.log("The Base64-encoded string that represents the current document has been written to the text box. To validate the string, use the \"Create workbook from string\" button.");
- }
- }
-
- function getFileContents(
- file: Office.File,
- onSuccess: (byteArray: number[]) => void,
- onError: (error: Office.Error) => void
- ) {
- let expectedSliceCount = file.sliceCount;
- let fileSlices: Array> = [];
-
- console.log("Current file size in bytes: " + file.size);
- console.log("Number of file slices: " + file.sliceCount);
-
- getFileContentsHelper();
-
- function getFileContentsHelper() {
- file.getSliceAsync(fileSlices.length, function (result) {
- if (result.status === Office.AsyncResultStatus.Failed) {
- file.closeAsync();
- return onError(result.error);
- }
-
- // Got one slice, store it in a temporary array.
- fileSlices.push(result.value.data);
-
- if (fileSlices.length == expectedSliceCount) {
- console.log("All slices have been received.");
- file.closeAsync();
-
- let array = [];
- fileSlices.forEach(slice => {
- array = array.concat(slice);
- });
-
- onSuccess(array);
- } else {
- getFileContentsHelper();
- }
- });
- }
- }
-
- async function newWorkbookFromFile() {
- await Excel.createWorkbook($('#file-contents').text()).catch(function (error) {
- console.error(error);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let expensesTable = sheet.tables.add('A1:E1', true);
- expensesTable.name = "SalesTable";
-
- expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- expensesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- createChart(context);
- sheet.activate();
-
- await context.sync();
- });
- }
-
- async function createChart(context: Excel.RequestContext) {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const salesTable = sheet.tables.getItem("SalesTable");
-
- const dataRange = salesTable.getDataBodyRange();
-
- let chart = sheet.charts.add("ColumnClustered", dataRange, Excel.ChartSeriesBy.columns);
-
- chart.setPosition("A15", "F30");
- chart.title.text = "Quarterly sales chart";
- chart.legend.position = "Right"
- chart.legend.format.fill.setSolidColor("white");
- chart.dataLabels.format.font.size = 15;
- chart.dataLabels.format.font.color = "black";
- let points = chart.series.getItemAt(0).points;
- points.getItemAt(0).format.fill.setSolidColor("pink");
- points.getItemAt(1).format.fill.setSolidColor("indigo");
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
- declare namespace base64js {
- /** Takes a byte array and returns a Base64 string
- * Imported from https://www.npmjs.com/package/base64-js package. */
- function fromByteArray(array: number[]): string;
- }
- language: typescript
-template:
- content: |
-
-
This sample shows how to get the Base64-encoded string that represents the current document. It uses the getFileAsync() method to read the file in slices and then joins all slices back together to form the complete file.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
-
-
Create a new workbook
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
-
- #file-contents {
- display: none;
- width: 100%;
- height: 10em;
- }
- language: css
-libraries: |-
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
-
- https://unpkg.com/base64-js@1.2.1/base64js.min.js
diff --git a/samples/excel/26-document/properties.yaml b/samples/excel/26-document/properties.yaml
deleted file mode 100644
index 3e34550fb..000000000
--- a/samples/excel/26-document/properties.yaml
+++ /dev/null
@@ -1,187 +0,0 @@
-order: 2
-id: excel-document-properties
-name: Properties
-description: Gets and sets document properties.
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |
- $("#set-doc-properties").click(() => tryCatch(setDocProperties));
- $("#get-doc-properties").click(() => tryCatch(getDocProperties));
- $("#set-custom-doc-properties").click(() => tryCatch(setCustomDocProperties));
- $("#get-custom-doc-properties").click(() => tryCatch(getCustomDocProperties));
- $("#get-count-custom-doc-properties").click(() => tryCatch(getCountCustomDocProperties));
-
- async function setDocProperties() {
- await Excel.run(async (context) => {
- let titleValue = "Excel document properties API";
- let subjectValue = "Set and get document properties";
- let keywordsValue = "Set and get operations";
- let commentsValue = "This is an Excel document properties API code sample";
- let categoryValue = "Office Add-ins";
- let managerValue = "John";
- let companyValue = "Microsoft";
-
- let docProperties = context.workbook.properties;
-
- // Set the writeable document properties.
- docProperties.title = titleValue;
- docProperties.subject = subjectValue;
- docProperties.keywords = keywordsValue;
- docProperties.comments = commentsValue;
- docProperties.category = categoryValue;
- docProperties.manager = managerValue;
- docProperties.company = companyValue;
-
- await context.sync();
-
- console.log("Set the following document properties: title, subject, keywords, comments, category, manager, company.");
- });
- }
-
- async function getDocProperties() {
- await Excel.run(async (context) => {
- let docProperties = context.workbook.properties;
-
- // Load a combination of read-only
- // and writeable document properties.
- docProperties.load("author, lastAuthor, revisionNumber, title, subject, keywords, comments, category, manager, company, creationDate");
-
- await context.sync();
-
- // Write the document properties to the console.
- // To learn how to view document properties in the UI,
- // see https://support.office.com/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75
- console.log("Author: " + docProperties.author);
- console.log("Last author : " + docProperties.lastAuthor);
- console.log("Revision number: " + docProperties.revisionNumber);
- console.log("Title: " + docProperties.title);
- console.log("Subject: " + docProperties.subject);
- console.log("Keywords: " + docProperties.keywords);
- console.log("Comments: " + docProperties.comments);
- console.log("Category: " + docProperties.category);
- console.log("Manager: " + docProperties.manager);
- console.log("Company: " + docProperties.company);
- console.log("Workbook creation date: " + docProperties.creationDate.toDateString());
- });
- }
-
- async function setCustomDocProperties() {
- await Excel.run(async (context) => {
- let customDocProperties = context.workbook.properties.custom;
-
- // Add custom document properties.
- customDocProperties.add("Introduction", "Hello");
- customDocProperties.add("Integer", "12");
-
- await context.sync();
-
- console.log("Successfully set custom document properties.");
- });
- }
-
- async function getCustomDocProperties() {
- await Excel.run(async (context) => {
- let customDocProperties = context.workbook.properties.custom;
- let customProperty = customDocProperties.getItem("Introduction");
- customProperty.load("key, value");
-
- await context.sync();
-
- // Write the custom document properties to the console.
- // To learn how to view document properties in the UI,
- // see https://support.office.com/article/View-or-change-the-properties-for-an-Office-file-21D604C2-481E-4379-8E54-1DD4622C6B75
- console.log("Custom key : " + customProperty.key);
- console.log("Custom value : " + customProperty.value);
-
- });
- }
-
- async function getCountCustomDocProperties() {
- await Excel.run(async (context) => {
-
- let customDocProperties = context.workbook.properties.custom;
-
- let count = customDocProperties.getCount();
-
- await context.sync();
-
- console.log("Count of custom document properties :" + count.value);
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |+
-
-
This sample shows how to set and get document properties.
-
-
-
-
Try it out
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/data-change-event-details.yaml b/samples/excel/30-events/data-change-event-details.yaml
deleted file mode 100644
index b85591d2d..000000000
--- a/samples/excel/30-events/data-change-event-details.yaml
+++ /dev/null
@@ -1,116 +0,0 @@
-order: 6
-id: excel-data-change-event-details
-name: Data changed event details
-description: Uses the onChanged event of a table to determine the specifics of changes.
-host: EXCEL
-api_set:
- ExcelApi: '1.9'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#register-handler").click(() => tryCatch(registerChangeEventHandler));
-
- async function registerChangeEventHandler() {
- await Excel.run(async (context) => {
- const expensesTable = context.workbook.worksheets.getActiveWorksheet().tables.getItem("ExpensesTable");
-
- // This event fires when a user edits a cell in the table.
- expensesTable.onChanged.add(onTableChanged);
- await context.sync();
-
- console.log("Added onChanged handler");
- });
- }
-
- async function onTableChanged(eventArgs: Excel.TableChangedEventArgs) {
- await Excel.run(async (context) => {
- const details = eventArgs.details;
- const address = eventArgs.address;
-
- console.log(`Change at ${address}: was ${details.valueBefore}(${details.valueTypeBefore}),`
- + ` now is ${details.valueAfter}(${details.valueTypeAfter})`);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/);
- expensesTable.name = "ExpensesTable";
-
- expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]];
-
- expensesTable.rows.add(null /*add at the end*/, [
- ["4/1/2017", "The Phone Company", "Communications", "$120"],
- ["4/2/2017", "Northwind Electric Cars", "Transportation", "$142"],
- ["4/5/2017", "Best For You Organics Company", "Groceries", "$27"],
- ["4/10/2017", "Coho Vineyard", "Restaurant", "$33"],
- ["4/11/2017", "Bellows College", "Education", "$350"],
- ["4/15/2017", "Trey Research", "Other", "$135"],
- ["4/15/2017", "Best For You Organics Company", "Groceries", "$97"]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to use table changed events.
-
-
-
-
Setup
-
-
-
-
Try it out
-
-
-
Edit individual cells in the table to trigger the event and see the console output.
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/data-changed.yaml b/samples/excel/30-events/data-changed.yaml
deleted file mode 100644
index f70d88e7a..000000000
--- a/samples/excel/30-events/data-changed.yaml
+++ /dev/null
@@ -1,120 +0,0 @@
-order: 5
-id: excel-events-data-changed
-name: Data changed event
-description: Registers an event handler that runs when data is changed.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.4'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#register-data-changed-handler").click(() => tryCatch(registerDataChangedHandler));
-
- async function registerDataChangedHandler() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const salesTable = sheet.tables.getItem("SalesTable");
- const salesByQuarterBinding = context.workbook.bindings.add(salesTable.getRange(), "Table", "SalesByQuarter");
- salesByQuarterBinding.onDataChanged.add(onSalesDataChanged);
-
- console.log("The data changed handler is registered.");
-
- await context.sync();
- });
- }
-
- async function onSalesDataChanged(eventArgs: Excel.BindingDataChangedEventArgs) {
- await Excel.run(async (context) => {
- console.log("Data was changed with binding " + eventArgs.binding.id);
-
- // Get the name of the table that's changed.
- const table: Excel.Table = context.workbook.bindings.getItem(eventArgs.binding.id).getTable();
- table.load("name");
-
- await context.sync();
- console.log("Name of the changed table: " + table.name);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let salesTable = sheet.tables.add('A1:E1', true);
- salesTable.name = "SalesTable";
- salesTable.getHeaderRowRange().values = [["Sales Team", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- salesTable.rows.add(null, [
- ["London", 500, 700, 654, null ],
- ["Hong Kong", 400, 323, 276, null ],
- ["New York", 1200, 876, 845, null ],
- ["Port-of-Spain", 600, 500, 854, null ],
- ["Nairobi", 5001, 2232, 4763, null ]
- ]);
-
- salesTable.getRange().format.autofitColumns();
- salesTable.getRange().format.autofitRows();
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register and use a handler for the data-changed event.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/event-column-and-row-sort.yaml b/samples/excel/30-events/event-column-and-row-sort.yaml
deleted file mode 100644
index bc2f39981..000000000
--- a/samples/excel/30-events/event-column-and-row-sort.yaml
+++ /dev/null
@@ -1,201 +0,0 @@
-order: 3
-id: excel-event-column-and-row-sort
-name: Column and row sort events
-description: Registers event handlers that run when column or row sorting events occur in the current worksheet.
-host: EXCEL
-api_set:
- ExcelApi: '1.10'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup)); $("#register-sort-handlers").click(() => tryCatch(registerSortHandlers)); $("#register-row-sort-handler").click(() => tryCatch(registerRowSortHandler)); $("#register-column-sort-handler").click(() => tryCatch(registerColumnSortHandler)); $("#sort-q1").click(() => tryCatch(sortTopToBottom, "Q1")); $("#sort-q3").click(() => tryCatch(sortTopToBottom, "Q3")); $("#sort-apples").click(() => tryCatch(sortLeftToRight, "Apples")); $("#sort-quinces").click(() => tryCatch(sortLeftToRight, "Quinces"));
- async function registerSortHandlers() {
- registerRowSortHandler();
- registerColumnSortHandler();
- }
- async function registerRowSortHandler() {
- await Excel.run(async (context) => {
- console.log("Adding row handler");
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // This will fire whenever a row has been moved as the result of a sort action.
- sheet.onRowSorted.add((event) => {
- return Excel.run((context) => {
- console.log("Row sorted: " + event.address);
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Clear formatting for section, then highlight the sorted area.
- sheet.getRange("A1:E5").format.fill.clear();
- if (event.address !== "") {
- sheet.getRanges(event.address).format.fill.color = "yellow";
- }
-
- return context.sync();
- });
- });
- });
- }
-
- async function registerColumnSortHandler() {
- await Excel.run(async (context) => {
- console.log("Adding column handler");
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // This will fire whenever a column has been moved as the result of a sort action.
- sheet.onColumnSorted.add((event) => {
- return Excel.run((context) => {
- console.log("Column sorted: " + event.address);
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Clear formatting for section, then highlight the sorted area.
- sheet.getRange("A1:E5").format.fill.clear();
- if (event.address !== "") {
- sheet.getRanges(event.address).format.fill.color = "yellow";
- }
-
- return context.sync();
- });
- });
- });
- }
-
- async function sortTopToBottom(criteria: string) {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const range = sheet.getRange("A1:E5");
-
- // Find the column header that provides the sort criteria.
- const header = range.find(criteria, {});
- header.load("columnIndex");
- await context.sync();
-
- range.sort.apply(
- [
- {
- key: header.columnIndex,
- sortOn: Excel.SortOn.value
- }
- ],
- false /*matchCase*/,
- true /*hasHeaders*/,
- Excel.SortOrientation.rows
- );
- await context.sync();
- });
- }
-
- async function sortLeftToRight(criteria: string) {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const range = sheet.getRange("A1:E5");
-
- // Find the row header that provides the sort criteria.
- const header = range.find(criteria, {});
- header.load("rowIndex");
- await context.sync();
-
- range.sort.apply(
- [
- {
- key: header.rowIndex,
- sortOn: Excel.SortOn.value
- }
- ],
- false /*matchCase*/,
- true /*hasHeaders*/,
- Excel.SortOrientation.columns
- );
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const data = [
- ["Fruit Sales", "Q1", "Q2", "Q3", "Q4"],
- ["Apples", 5000, 2000, 1000, 7500],
- ["Pears", 2000, 900, 550, 1800],
- ["Quinces", 500, 800, 400, 100],
- ["Plums", 600, 700, 8000, 900]
- ];
-
- sheet.getRanges("A1:E1,A2:A5").format.font.bold = true;
- const range = sheet.getRange("A1:E5");
- range.values = data;
- range.format.autofitColumns();
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback, option?) {
- try {
- await callback(option);
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register and use handlers for the column and row sorting events.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
The event handlers will highlight any rows or columns moved as part of a sorting operation.
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/event-worksheet-single-click.yaml b/samples/excel/30-events/event-worksheet-single-click.yaml
deleted file mode 100644
index 6e13acac6..000000000
--- a/samples/excel/30-events/event-worksheet-single-click.yaml
+++ /dev/null
@@ -1,77 +0,0 @@
-order: 11
-id: excel-event-worksheet-single-click
-name: Single click event
-description: Registers an event handler that runs when a single-click event occurs in the current worksheet.
-host: EXCEL
-api_set:
- ExcelApi: '1.10'
-script:
- content: |-
- $("#register-click-handler").click(() => tryCatch(registerClickHandler));
-
- async function registerClickHandler() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- sheet.onSingleClicked.add((event) => {
- return Excel.run((context) => {
- console.log(`Click detected at ${event.address} (pixel offset from upper-left cell corner: ${event.offsetX}, ${event.offsetY})`);
- return context.sync();
- });
- });
-
- console.log("The worksheet click handler is registered.");
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register and use a handler for the single-click event.
-
-
-
-
Try it out
-
Use the button below to register the event handler. Then, left-click around the worksheet and check the console.
-
This sample shows how to register and use handlers for the Chart onActivated and onDeactivated events.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
Click the button to register handlers for the pie chart's activated and deactivated events. Then click the chart to activate it. Watch the console. Finally, click the cylinder chart to deactivate the pie chart.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-chartcollection-added-activated.yaml b/samples/excel/30-events/events-chartcollection-added-activated.yaml
deleted file mode 100644
index f96ad0f9f..000000000
--- a/samples/excel/30-events/events-chartcollection-added-activated.yaml
+++ /dev/null
@@ -1,163 +0,0 @@
-order: 1
-id: excel-events-chartcollection-added-activated
-name: Chart collection events
-description: 'Registers event handlers on a worksheet''s chart collection that run when any chart within is activated or deactivated, as well as when charts are added to or deleted from the collection.'
-host: EXCEL
-api_set:
- ExcelApi: '1.8'
-script:
- content: |-
- $("#setup").click(() => tryCatch(setup));
- $("#register-chartcollection-handlers").click(() => tryCatch(registerChartCollectionHandlers));
- $("#add-chart").click(() => tryCatch(createPieChart));
-
- async function registerChartCollectionHandlers() {
- await Excel.run(async (context) => {
-
- context.workbook.worksheets.getActiveWorksheet().charts.onAdded.add(chartAdded);
- context.workbook.worksheets.getActiveWorksheet().charts.onActivated.add(chartActivated);
- context.workbook.worksheets.getActiveWorksheet().charts.onDeactivated.add(chartDeactivated);
- context.workbook.worksheets.getActiveWorksheet().charts.onDeleted.add(chartDeleted);
-
- await context.sync();
-
- console.log("Added handlers for ChartCollection onActivated,onAdded, onDeleted, and onDeactivated events.");
- });
- }
-
- async function chartAdded(event) {
- await Excel.run(async (context) => {
- console.log("A chart has been added with ID: " + event.chartId);
- });
- }
-
- async function chartActivated(event) {
- await Excel.run(async (context) => {
- console.log("The ID of the active chart is: " + event.chartId);
- });
- }
-
- async function chartDeactivated(event) {
- await Excel.run(async (context) => {
- console.log("The chart with this ID was deactivated: " + event.chartId);
- });
- }
-
- async function chartDeleted(event) {
- await Excel.run(async (context) => {
- console.log("The chart with this ID was deleted: " + event.chartId);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
-
- let expensesTable = sheet.tables.add('A1:E1', true);
- expensesTable.name = "SalesTable";
-
- expensesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- expensesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
- await context.sync();
- });
- }
-
- async function createPieChart() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const salesTable = sheet.tables.getItem("SalesTable");
- const dataRange = salesTable.getDataBodyRange();
-
- let chart = sheet.charts.add("Pie", dataRange, "Auto");
-
- chart.name = "Pie";
- chart.setPosition("A10", "F25");
- chart.title.text = "1st Quarter sales chart";
- chart.legend.position = "Bottom"
- chart.legend.format.fill.setSolidColor("white");
- chart.dataLabels.format.font.size = 15;
- chart.dataLabels.format.font.color = "black";
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register and use handlers for the ChartCollection onAdded, onDeleted, onActivated, and onDeactivated events.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
Click the button to register and use handlers for the worksheet's ChartCollection events.
-
-
Click the second button to programmatically add a chart and see the onAdded event fire. Watch the console.
-
-
Manually add another chart. You can use the same the table as a source. Watch the console.
-
Select one of the charts to see the onActivated event fire. Then select the other chart to see the onDeactivated event fire on one chart and onActivated for the other.
-
Delete one of the charts to see the onDeleted event fire.
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/events-comment-event-handler.yaml b/samples/excel/30-events/events-comment-event-handler.yaml
deleted file mode 100644
index 76f7a5223..000000000
--- a/samples/excel/30-events/events-comment-event-handler.yaml
+++ /dev/null
@@ -1,181 +0,0 @@
-order: 4
-id: excel-events-comments
-name: Comment events
-description: 'Registers event handlers to listen for comment additions, changes, and deletions.'
-host: EXCEL
-api_set:
- ExcelAPI: '1.12'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#register-event-handlers").click(() => tryCatch(registerEventHandlers));
- $("#add-comment").click(() => tryCatch(addComment));
- $("#edit-comment").click(() => tryCatch(editComment));
- $("#delete-comment").click(() => tryCatch(deleteComment));
-
- async function registerEventHandlers() {
- await Excel.run(async (context) => {
- const comments = context.workbook.worksheets.getActiveWorksheet().comments;
-
- // Register the onAdded, onChanged, and onDeleted comment event handlers.
- comments.onAdded.add(commentAdded);
- comments.onChanged.add(commentChanged);
- comments.onDeleted.add(commentDeleted);
-
- await context.sync();
-
- console.log("Added event handlers for when comments are added, changed, or deleted.");
- });
- }
-
- async function commentAdded(event: Excel.CommentAddedEventArgs) {
- // Retrieve the added comment using the comment ID.
- // Note: This function assumes only a single comment is added at a time.
- await Excel.run(async (context) => {
- const addedComment = context.workbook.comments.getItem(event.commentDetails[0].commentId);
-
- // Load the added comment's data.
- addedComment.load(["content", "authorName", "creationDate"]);
-
- await context.sync();
-
- // Print out the added comment's data.
- console.log(`A comment was added:`);
- console.log(` ID: ${event.commentDetails[0].commentId}`);
- console.log(` Comment content:${addedComment.content}`);
- console.log(` Comment author:${addedComment.authorName}`);
- console.log(` Creation date:${addedComment.creationDate}`);
- });
- }
-
- async function commentChanged(event: Excel.CommentChangedEventArgs) {
- // Retrieve the changed comment using the comment ID.
- // Note: This function assumes only a single comment is changed at a time.
- await Excel.run(async (context) => {
- const changedComment = context.workbook.comments.getItem(event.commentDetails[0].commentId);
-
- // Load the changed comment's data.
- changedComment.load(["content", "authorName", "creationDate"]);
-
- await context.sync();
-
- // Print out the changed comment's data.
- console.log(`A comment was changed:`);
- console.log(` ID: ${event.commentDetails[0].commentId}`);
- console.log(` Updated comment content: ${changedComment.content}`);
- console.log(` Comment author: ${changedComment.authorName}`);
- console.log(` Creation date: ${changedComment.creationDate}`);
- });
- }
-
- async function commentDeleted(event: Excel.CommentDeletedEventArgs) {
- // Print out the deleted comment's ID.
- // Note: This function assumes only a single comment is deleted at a time.
- await Excel.run(async (context) => {
- console.log(`A comment was deleted:`);
- console.log(` ID: ${event.commentDetails[0].commentId}`);
- });
- }
-
- async function addComment() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Comments");
-
- // Note that an InvalidArgument error will be thrown if multiple cells are passed to `comment.add`.
- sheet.comments.add("A1", "To do: add data.");
- await context.sync();
- });
- }
-
- async function editComment() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Comments");
- const comment = sheet.comments.getItemAt(0);
- comment.content = "Please add headers here.";
- await context.sync();
- });
- }
-
- async function deleteComment() {
- await Excel.run(async (context) => {
- context.workbook.comments.getItemByCell("Comments!A1").delete();
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Comments").delete();
- const sheet = context.workbook.worksheets.add("Comments");
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register event handlers to listen for comment additions, changes, and deletions.
-
-
-
Setup
-
-
-
-
-
-
Try it out
-
In addition to hovering over a cell, you can view comment changes in the Comments pane by selecting Show Comments from the Review tab.
-
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-disable-events.yaml b/samples/excel/30-events/events-disable-events.yaml
deleted file mode 100644
index b97d09ca1..000000000
--- a/samples/excel/30-events/events-disable-events.yaml
+++ /dev/null
@@ -1,187 +0,0 @@
-order: 7
-id: excel-events-disable-events
-name: Enable and disable events
-description: Toggles event firing on and off.
-host: EXCEL
-api_set:
- ExcelApi: '1.8'
-script:
- content: |
- $("#toggleEvents").click(() => tryCatch(toggleEvents));
- $("#setup").click(() => tryCatch(setup));
- $("#refreshData").click(() => tryCatch(addOrRefreshData));
- $("#registerSumChangedHandlers").click(() => tryCatch(registerSumChangedHandlers));
-
- async function toggleEvents() {
- await Excel.run(async (context) => {
- context.runtime.load("enableEvents");
- await context.sync();
-
- // check if events are enabled and toggle accordingly
- const eventBoolean = !context.runtime.enableEvents
- context.runtime.enableEvents = eventBoolean;
- if (eventBoolean) {
- console.log("Events are currently on.");
- } else {
- console.log("Events are currently off.");
- }
-
- await context.sync();
- });
- }
-
- async function registerSumChangedHandlers() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const sumRange = sheet.getRange("B20:P20");
- sumRange.load("columnCount");
- await context.sync();
-
- // add an event handler to each cell in the sum range
- for (let i = 0; i < sumRange.columnCount; i++) {
- let sumBinding = context.workbook.bindings.add(sumRange.getCell(0,i), Excel.BindingType.range, "SumBinding" + i);
- sumBinding.onDataChanged.add(onSumChanged);
- }
- await context.sync();
- });
- }
-
- async function onSumChanged(eventArgs: Excel.BindingDataChangedEventArgs) {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const cell = sheet.getRange("P21");
-
- // get the grand total of the whole sum range
- // note that we are having this program perform the sum instead of giving the Excel cell a function,
- // this gives us updating control
- let x = context.workbook.functions.sum(sheet.getRange("B20:P20"));
- x.load("value");
- await context.sync();
-
- cell.values = [[x.value]];
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let infoRange = sheet.getRange("A20:A21");
- infoRange.values = [["Sums"], ["Grand Total"]]
- infoRange.format.autofitColumns();
- infoRange.format.font.bold = true;
- addOrRefreshData();
- addSumRow();
- sheet.activate();
- await context.sync();
- });
- }
-
- async function addOrRefreshData() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const dataRange = sheet.getRange("B1:P19");
- dataRange.load(["rowCount", "columnCount"]);
- await context.sync();
-
- // fill the range with random numbers
- for (let i = 0; i < dataRange.rowCount; i++) {
- for (let j = 0; j < dataRange.columnCount; j++) {
- dataRange.getCell(i, j).values = [[Math.round(Math.random() * 100)]];
- }
- }
-
- await context.sync();
- });
- }
-
- async function addSumRow() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const dataRange = sheet.getRange("B1:P19");
- dataRange.load("rowCount");
-
- // add a sum of each column to the top
- const sumRange = sheet.getRange("B20:P20");
- sumRange.load(["columnCount"]);
- await context.sync();
-
- for (let i = 0; i < sumRange.columnCount; i++) {
- const formulaCell = sumRange.getCell(0, i);
- const startAddressCell = dataRange.getCell(0, i);
- const endAddressCell = dataRange.getCell(dataRange.rowCount - 1, i);
- startAddressCell.load("address");
- endAddressCell.load("address");
- await context.sync();
- formulaCell.formulas = [["=SUM(" + startAddressCell.address + ":" + endAddressCell.address + ")"]];
- formulaCell.format.font.bold = true;
- }
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to turn events on and off.
-
-
-
Setup
-
-
-
-
-
Try it out
-
The handlers update the "Grand Total" cell when events are fired (and enabled). Try editing the cells or refreshing the data with events enabled and disabled.
-
-
-
Please wait until all the numbers are written to the range before pressing Refresh data again.
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |-
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-formula-changed.yaml b/samples/excel/30-events/events-formula-changed.yaml
deleted file mode 100644
index b9bcd3c85..000000000
--- a/samples/excel/30-events/events-formula-changed.yaml
+++ /dev/null
@@ -1,131 +0,0 @@
-order: 8
-id: excel-events-formula-changed
-name: Formula changed event
-description: Registers an event handler to detect changes to formulas.
-host: EXCEL
-api_set:
- ExcelAPI: '1.13'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#register-formula-change-handler").click(() => tryCatch(registerFormulaChangeHandler));
- $("#trigger-formula-change").click(() => tryCatch(triggerFormulaChange));
-
- async function registerFormulaChangeHandler() {
- await Excel.run(async (context) => {
- // Retrieve the worksheet named "Sample".
- let sheet = context.workbook.worksheets.getItem("Sample");
-
- // Register the formula changed event handler for this worksheet.
- sheet.onFormulaChanged.add(formulaChangeHandler);
- await context.sync();
-
- console.log("Registered a formula changed event handler for this worksheet.");
- });
- }
-
- async function formulaChangeHandler(event: Excel.WorksheetFormulaChangedEventArgs) {
- await Excel.run(async (context) => {
- // Retrieve details about the formula change event.
- const cellAddress = event.formulaDetails[0].cellAddress;
- const previousFormula = event.formulaDetails[0].previousFormula;
- const source = event.source;
-
- // Print out the change event details.
- console.log(
- `The formula in cell ${cellAddress} changed.
- The previous formula was: ${previousFormula}.
- The source of the change was: ${source}.`
- );
- });
- }
-
- async function triggerFormulaChange() {
- await Excel.run(async (context) => {
- // Retrieve the worksheet and choose a range to edit.
- let sheet = context.workbook.worksheets.getItem("Sample");
- const range = sheet.getRange("D1");
-
- // Change the formula in the chosen range.
- range.formulas = [["=A1 * C1"]];
- await context.sync();
-
- console.log(`The new formula is: ${range.formulas}`);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Delete "Sample" worksheet, if it already exists.
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
-
- // Add a worksheet named "Sample".
- const sheet = context.workbook.worksheets.add("Sample");
-
- // Retrieve the range.
- const range = sheet.getRange("A1:D1");
-
- // Add sample data to the range.
- range.formulas = [["2", "4", "24", "=A1 * B1"]];
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register a formula changed event handler and detect details about the changed formula.
-
-
-
Try it out
-
Set up the worksheet.
-
-
Register the formula changed event handler to this worksheet.
-
-
Trigger a change to the formula in cell D1. Watch the console to see details about the change event.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-table-changed.yaml b/samples/excel/30-events/events-table-changed.yaml
deleted file mode 100644
index c7d4caf33..000000000
--- a/samples/excel/30-events/events-table-changed.yaml
+++ /dev/null
@@ -1,177 +0,0 @@
-order: 12
-id: excel-events-table-changed
-name: Table events
-description: Registers event handlers that run when a table is changed or selected.
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |+
- $("#setup").click(() => tryCatch(setup));
- $("#register-on-changed-handler").click(() => tryCatch(registerOnChangedHandler));
- $("#change-data").click(() => tryCatch(changeData));
- $("#register-on-selection-changed-handler").click(() => tryCatch(registerOnSelectionChangedHandler));
- $("#change-selection").click(() => tryCatch(changeSelection));
-
- async function registerOnChangedHandler() {
- await Excel.run(async (context) => {
- let table = context.workbook.tables.getItemAt(0);
- table.onChanged.add(onChange);
-
- await context.sync();
- console.log("A handler has been registered for the onChanged event");
- });
- }
-
- async function changeData() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- let range = sheet.getRange("B7");
- range.values = [[900]];
- range.format.autofitColumns();
-
- await context.sync();
- console.log("B7 value has been changed.");
- });
- }
-
- async function onChange(event) {
- await Excel.run(async (context) => {
- console.log("Handler for table onChanged event has been triggered. Data changed address: " + event.address);
- });
- }
-
- async function registerOnSelectionChangedHandler() {
- await Excel.run(async (context) => {
- let table = context.workbook.tables.getItemAt(0);
- table.onSelectionChanged.add(onSelectionChange);
-
- await context.sync();
- console.log("A handler has been registered for table onSelectionChanged event");
- });
- }
-
- async function changeSelection() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getActiveWorksheet();
- let range = sheet.getRange("B3:C3");
- range.select();
-
- await context.sync();
- });
- }
-
- async function onSelectionChange(args) {
- await Excel.run(async (context) => {
- console.log("Handler for table onSelectionChanged event has been triggered. The new selection is: " + args.address);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let salesTable = sheet.tables.add('A1:E1', true);
- salesTable.name = "SalesTable";
-
- salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- salesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
-
-
- language: typescript
-template:
- content: |+
-
-
This sample shows how to register and use event handlers for table onChanged and onSelectionChanged events.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
Changing data in a table triggers the data changed event. You can change the data manually or programmatically.
-
-
-
-
-
-
-
-
-
Changing a range selection in a table triggers the table onSelectionChanged event. You can change selection manually or programmatically.
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-tablecollection-changed.yaml b/samples/excel/30-events/events-tablecollection-changed.yaml
deleted file mode 100644
index e0662c26e..000000000
--- a/samples/excel/30-events/events-tablecollection-changed.yaml
+++ /dev/null
@@ -1,170 +0,0 @@
-order: 10
-id: excel-events-tablecollection-changed
-name: Table collection events
-description: Registers an event handler that runs when a table collection is changed.
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |+
- $("#setup").click(() => tryCatch(setup));
- $("#register-on-changed-handler").click(() => tryCatch(registerOnChangedHandler));
- $("#change-data").click(() => tryCatch(changeData));
-
- async function registerOnChangedHandler() {
- await Excel.run(async (context) => {
- let tables = context.workbook.tables;
- tables.onChanged.add(onChange);
-
- await context.sync();
- console.log("A handler has been registered for the table collection onChanged event");
- });
- }
-
- async function changeData() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
-
- // Change two values to trigger two table onChanged events for demonstration purposes.
- // You can also change only one value by commenting out one of the ranges.
- let range1 = sheet.getRange("B7");
- let range2 = sheet.getRange("C15");
- range1.values = [[900]];
- range2.values = [[20]];
- range1.format.autofitColumns();
- range2.format.autofitColumns();
-
- await context.sync();
- });
- }
-
- async function onChange(event) {
- await Excel.run(async (context) => {
- let table = context.workbook.tables.getItem(event.tableId);
- let worksheet = context.workbook.worksheets.getItem(event.worksheetId);
- worksheet.load("name");
-
- await context.sync();
-
- console.log("Handler for table collection onChanged event has been triggered. Data changed address: " + event.address);
- console.log("Table Id : " + event.tableId);
- console.log("Worksheet Id : " + worksheet.name);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- createSalesTable(sheet);
- createReturnsTable(sheet);
-
- let format = sheet.getRange().format;
- format.autofitColumns();
- format.autofitRows();
-
- sheet.activate();
- await context.sync();
- });
- }
-
- function createSalesTable(sheet: Excel.Worksheet) {
- let salesTable = sheet.tables.add('A1:E1', true);
- salesTable.name = "SalesTable";
-
- salesTable.getHeaderRowRange().values = [["Sales", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- salesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]
- ]);
- }
-
- function createReturnsTable(sheet: Excel.Worksheet) {
- let returnsTable = sheet.tables.add('A10:E10', true);
- returnsTable.name = "ReturnsTable";
-
- returnsTable.getHeaderRowRange().values = [["Returns", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- returnsTable.rows.add(null, [
- ["Frames", 50, 70, 65, 77],
- ["Saddles", 20, 23, 16, 31],
- ["Brake levers", 20, 87, 56, 81],
- ["Chains", 15, 18, 32, 33],
- ["Mirrors", 15, 60, 23, 54],
- ["Spokes", 25, 35, 45, 65]
- ]);
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
-
-
- language: typescript
-template:
- content: |+
-
-
This sample shows how to register and use an event handler for table collection onChanged event.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
Changing data in tables triggers the data changed event. You can change the data manually or programmatically.
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-workbook-activated.yaml b/samples/excel/30-events/events-workbook-activated.yaml
deleted file mode 100644
index 94979e2c8..000000000
--- a/samples/excel/30-events/events-workbook-activated.yaml
+++ /dev/null
@@ -1,80 +0,0 @@
-order: 13
-id: excel-events-workbook-activated
-name: Workbook activated event
-description: This sample shows how to register a workbook activated event handler.
-host: EXCEL
-api_set:
- ExcelAPI: '1.13'
-script:
- content: |
- $("#register-event-handler").click(() => tryCatch(registerEventHandler));
-
- async function workbookActivated(event: Excel.WorkbookActivatedEventArgs) {
- await Excel.run(async (context) => {
- // Callback function for when the workbook is activated.
- console.log("The workbook was activated.");
- });
- }
-
- async function registerEventHandler() {
- await Excel.run(async (context) => {
- const workbook = context.workbook;
-
- // Register the workbook activated event handler.
- workbook.onActivated.add(workbookActivated);
-
- await context.sync();
- console.log("Added event handler for workbook activated.");
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register a workbook activated event handler.
-
Once the event handler is registered, a notification prints to the console when the workbook is activated. Try
- switching to another application and then switching back to Excel to see the console notification.
-
-
-
-
Try it out
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml b/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml
deleted file mode 100644
index 1e2661035..000000000
--- a/samples/excel/30-events/events-workbook-and-worksheet-collection.yaml
+++ /dev/null
@@ -1,238 +0,0 @@
-order: 14
-id: excel-events-workbook-and-worksheet-collection
-name: Workbook and worksheet collection events
-description: 'Registers event handlers that run when a worksheet is added, activated, or deactivated, or when the settings of a workbook are changed.'
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |-
- $("#register-on-add-handler").click(() => tryCatch(registerOnAddHandler));
- $("#add-worksheet").click(() => tryCatch(addWorksheet));
-
- $("#register-on-activate-handler").click(() => tryCatch(registerOnActivateHandler));
- $("#register-on-deactivate-handler").click(() => tryCatch(registerOnDeactivateHandler));
- $("#delete-worksheet").click(() => tryCatch(deleteWorksheet));
-
- $("#create-setting").click(() => tryCatch(createSetting));
- $("#change-setting").click(() => tryCatch(changeSetting));
- $("#register-settings-changed-handler").click(() => tryCatch(registerSettingsChangedHandler));
-
- async function registerOnAddHandler() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets;
- sheet.onAdded.add(onWorksheetAdd);
-
- await context.sync();
- console.log("A handler has been registered for the OnAdded event.");
- });
- }
-
- async function addWorksheet() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.add();
- sheet.load("name, position");
-
- await context.sync();
- console.log('Added worksheet named "${sheet.name}" in position ${sheet.position}');
- });
- }
-
- async function onWorksheetAdd(event) {
- await Excel.run(async (context) => {
- console.log(
- "Handler for worksheet onAdded event has been triggered. Newly added worksheet Id : " +
- event.worksheetId
- );
- });
- }
-
- async function registerOnActivateHandler() {
- await Excel.run(async (context) => {
- let sheets = context.workbook.worksheets;
- sheets.onActivated.add(onActivate);
-
- await context.sync();
- console.log("A handler has been registered for the OnActivate event.");
- });
- }
-
- async function onActivate(args) {
- await Excel.run(async (context) => {
- console.log("The activated worksheet Id : " + args.worksheetId);
- });
- }
-
- async function registerOnDeactivateHandler() {
- await Excel.run(async (context) => {
- let sheets = context.workbook.worksheets;
- sheets.onDeactivated.add(onDeactivate);
-
- await context.sync();
- console.log("A handler has been registered for the OnDeactivate event.");
- });
- }
-
- async function onDeactivate(args) {
- await Excel.run(async (context) => {
- console.log("The deactivated worksheet Id : " + args.worksheetId);
- });
- }
-
- async function deleteWorksheet() {
- await Excel.run(async (context) => {
- // Deleting the current worksheet triggers the deactivate event and
- // the activate event for the preceding worksheet.
- let sheets = context.workbook.worksheets;
- sheets.load("items/name");
-
- await context.sync();
-
- if (sheets.items.length > 1) {
- let lastSheet = sheets.items[sheets.items.length - 1];
- lastSheet.delete();
- console.log(`Deleted worksheet named "${lastSheet.name}"`);
- } else {
- console.log("Unable to delete worksheet.");
- }
- });
- }
-
- async function createSetting() {
- await Excel.run(async (context) => {
- const settings = context.workbook.settings;
- settings.add("NeedsReview", true);
- const needsReview = settings.getItem("NeedsReview");
- needsReview.load("value");
-
- await context.sync();
- console.log("Setting value is: " + needsReview.value);
- });
- }
-
- async function registerSettingsChangedHandler() {
- await Excel.run(async (context) => {
- const settings = context.workbook.settings;
- settings.onSettingsChanged.add(onChangedSetting);
-
- await context.sync();
- console.log("Settings changed handler registered.");
- });
- }
-
- async function onChangedSetting(args: Excel.SettingsChangedEventArgs) {
- try {
- await Excel.run(async (context) => {
- const changedSetting = args.settings.getItem("NeedsReview");
- changedSetting.load("value");
-
- // Must sync with the context in the EventArgs object,
- // not the context that Office passes to Excel.run.
- await args.settings.context.sync();
-
- console.log("Setting value is: " + changedSetting.value);
- await context.sync();
- });
- }
- catch (error) {
- console.error(error);
- }
- }
-
- async function changeSetting() {
-
- // The settings.add method is also how you change a
- // setting. There is no settings.setItem or setting.set
- // method. For example:
- // await Excel.run(async (context) => {
- // const settings = context.workbook.settings;
- // settings.add("NeedsReview", false);
- // await context.sync();
- // });
- // However, a bug prevents the SettingsChanged event
- // from firing when a setting is changed with the
- // Excel 1.4 Settings APIs. So we must use the Settings
- // object from the Office shared APIs:
- Office.context.document.settings.set('NeedsReview', false);
- await Office.context.document.settings.saveAsync();
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register and use handlers for when a worksheet is added, activated, or deactivated, or when the settings of a workbook are changed.
-
-
-
-
Try it out
-
-
Added
-
-
-
-
-
-
Activated/Deactivated
-
-
-
-
-
Settings
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/30-events/events-worksheet-protection.yaml b/samples/excel/30-events/events-worksheet-protection.yaml
deleted file mode 100644
index 509e0a554..000000000
--- a/samples/excel/30-events/events-worksheet-protection.yaml
+++ /dev/null
@@ -1,111 +0,0 @@
-order: 16
-id: excel-events-worksheet-protection
-name: Worksheet protection events
-description: Registers an event handler to listen for worksheet protection status changes.
-host: EXCEL
-api_set:
- ExcelAPI: '1.14'
-script:
- content: |
- $("#register-event").click(() => tryCatch(registerEvent));
- $("#change-protection").click(() => tryCatch(changeProtection));
-
- async function registerEvent() {
- // This function registers an event handler for the onProtectionChanged event of a worksheet.
- await Excel.run(async (context) => {
- // Set "Sample" as the active worksheet.
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
- sheet.activate();
-
- // Register the onProtectionChanged event handler.
- sheet.onProtectionChanged.add(checkProtection);
- await context.sync();
- console.log("Added a worksheet protection change event handler.");
- });
- }
-
- async function checkProtection(event: Excel.WorksheetProtectionChangedEventArgs) {
- // This function is an event handler that returns the protection status of a worksheet
- // and information about the changed worksheet.
- await Excel.run(async (context) => {
- const protectionStatus = event.isProtected;
- const worksheetId = event.worksheetId;
- const source = event.source;
- console.log("Protection status changed. Protection status is now: " + protectionStatus + ".");
- console.log(" ID of changed worksheet: " + worksheetId + ".");
- console.log(" Source of change event: " + source + ".");
- });
- }
-
- async function changeProtection() {
- // This function toggles the protection status of a worksheet between "protected" and "unprotected".
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- sheet.activate();
-
- // Load the protected property of the WorksheetProtection object.
- sheet.load("protection/protected");
- await context.sync();
-
- // Enable worksheet protection if it's disabled, or disable worksheet protection if it's enabled.
- if (sheet.protection.protected) {
- sheet.protection.unprotect();
- } else {
- sheet.protection.protect();
- }
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register a worksheet protection change event handler. Once the event handler is registered, you can enable and disable worksheet protection for the current worksheet. When worksheet protection is enabled, the current worksheet can't be edited.
-
-
-
Try it out
-
-
-
Toggle worksheet protection and then try editing a cell on the worksheet.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/events-worksheet.yaml b/samples/excel/30-events/events-worksheet.yaml
deleted file mode 100644
index 682015fe7..000000000
--- a/samples/excel/30-events/events-worksheet.yaml
+++ /dev/null
@@ -1,234 +0,0 @@
-order: 15
-id: excel-events-worksheet
-name: Worksheet events
-description: 'Registers event handlers that run when data is changed in worksheet, the selected range changes in a worksheet, or the worksheet is recalculated.'
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |-
- $("#setup").click(() => tryCatch(setup));
-
- $("#register-on-selection-changed-handler").click(() => tryCatch(registerSelectionChangedHandler));
- $("#select-range").click(() => tryCatch(selectRange));
-
- $("#register-on-changed-handler").click(() => tryCatch(registerOnChangedHandler));
- $("#register-onCalculated-handler").click(() => tryCatch(registerOnCalculatedHandler));
- $("#recalculate").click(() => tryCatch(recalculate));
-
- $("#delete-data").click(() => tryCatch(deleteData));
-
- async function registerSelectionChangedHandler() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- sheet.onSelectionChanged.add(onSelectionChange);
- await context.sync();
-
- console.log("Added a worksheet-level selection change event handler.");
- });
- }
-
- async function selectRange() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- let range = sheet.getRange("B7:C7");
- range.select();
-
- await context.sync();
- });
- }
-
- async function onSelectionChange(event) {
- await Excel.run(async (context) => {
- console.log("The selected range has changed to: " + event.address);
- });
- }
-
- async function registerOnCalculatedHandler() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- sheet.onCalculated.add(onCalculated);
- await context.sync();
-
- console.log("Added a worksheet-level on-calculated event handler.");
- });
- }
-
- async function recalculate() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- let randomResult = context.workbook.functions.randBetween(1, 3000).load("value");
- await context.sync();
-
- let row = sheet.tables.getItem("SalesTable").rows.getItemAt(0);
- let newValue = [["Frames", 5000, 7000, 6544, randomResult.value, "=SUM(B2:E2)"]];
- row.values = newValue;
- row.load("values");
- await context.sync();
- });
- }
-
- async function onCalculated(event) {
- await Excel.run(async (context) => {
- console.log("The worksheet has recalculated.");
- });
- }
-
- async function registerOnChangedHandler() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- sheet.onChanged.add(onChange);
- await context.sync();
-
- console.log("Added a worksheet-level data-changed event handler.");
- });
- }
-
- async function changeData() {
- await Excel.run(async (context) => {
- let sheet = context.workbook.worksheets.getItem("Sample");
- let range = sheet.getRange("B5");
- range.values = [[800]];
- range.format.autofitColumns();
-
- await context.sync();
-
- console.log("B5 value has been changed.");
- });
- }
-
- async function deleteData() {
- // This function deletes data from a range and sets the delete shift direction to "up".
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const range = sheet.getRange("A5:F5");
- range.delete(Excel.DeleteShiftDirection.up);
- });
- }
-
- async function onChange(event: Excel.WorksheetChangedEventArgs) {
- // This function is an event handler that returns the address, trigger source,
- // and insert or delete shift directions of the change.
- await Excel.run(async (context) => {
- // Return the address where change occurred.
- console.log(`Handler for worksheet onChanged event has been triggered.`);
- console.log(` Data changed address: ` + event.address);
-
- // Return the source of the event that triggered the change.
- console.log(` Data change trigger source: ` + event.triggerSource);
-
- // Note:insertShiftDirection and deleteShiftDirection are exclusive and both enums can't have a value at the same time.
- // If one has a value, then the other will return undefined.
-
- // If the insert shift direction is defined, return it.
- if (event.changeDirectionState.insertShiftDirection) {
- console.log(` Cells inserted shift direction: ` + event.changeDirectionState.insertShiftDirection);
- }
-
- // If the delete shift direction is defined, return it.
- if (event.changeDirectionState.deleteShiftDirection) {
- console.log(` Cells deleted shift direction: ` + event.changeDirectionState.deleteShiftDirection);
- }
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let salesTable = sheet.tables.add("A1:F1", true);
- salesTable.name = "SalesTable";
-
- salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4", "Total"]];
-
- salesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377, "=SUM(B2:E2)"],
- ["Saddles", 400, 323, 276, 651, "=SUM(B3:E3)"],
- ["Brake levers", 12000, 8766, 8456, 9812, "=SUM(B4:E4)"],
- ["Chains", 1550, 1088, 692, 853, "=SUM(B5:E5)"],
- ["Mirrors", 225, 600, 923, 544, "=SUM(B6:E6)"],
- ["Spokes", 6005, 7634, 4589, 8765, "=SUM(B7:E7)"]
- ]);
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to register and use an event handler for the worksheet onSelectionChanged event.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
Selection Changed
-
-
-
Changed and Calculated
-
-
-
-
Detect insert and delete shift directions
-
Use the "Insert" and "Delete" buttons in the Excel UI to trigger the onChanged event. Or, use the following "Delete" button to see the properties returned by the event when a table row is removed.
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/30-events/selection-changed-events.yaml b/samples/excel/30-events/selection-changed-events.yaml
deleted file mode 100644
index 285379ebd..000000000
--- a/samples/excel/30-events/selection-changed-events.yaml
+++ /dev/null
@@ -1,160 +0,0 @@
-order: 9
-id: excel-selection-changed-events
-name: Selection changed events
-description: Registers handlers all the different `onSelectionChanged` events and displays how each event reports the selected addresses.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#register-event-handlers").click(() => tryCatch(registerEventHandlers));
-
- async function registerEventHandlers() {
- await Excel.run(async (context) => {
- // Add a selection changed event handler for the binding.
- let binding = context.workbook.bindings.getItemAt(0);
- binding.onSelectionChanged.add(onBindingSelectionChange);
-
- // Add a selection changed event handler for the table.
- let table = context.workbook.tables.getItemAt(0);
- table.onSelectionChanged.add(onTableSelectionChange);
-
- // Add a selection changed event handler for the worksheet.
- let sheet = context.workbook.worksheets.getItem("Sample");
- sheet.onSelectionChanged.add(onWorksheetSelectionChange);
-
- // Add a selection changed event handler for the worksheet collection.
- context.workbook.worksheets.onSelectionChanged.add(onWorksheetCollectionSelectionChange);
-
- await context.sync();
- });
- }
-
- async function onBindingSelectionChange(args: Excel.BindingSelectionChangedEventArgs) {
- await Excel.run(async (context) => {
- console.log(`Binding event: The new selection is\nStarting Column: ${args.startColumn}\nStarting Row: ${args.startRow}\nColumn Count: ${args.columnCount}\nRow Count: ${args.rowCount}`);
- });
- }
-
- async function onTableSelectionChange(args: Excel.TableSelectionChangedEventArgs) {
- await Excel.run(async (context) => {
- console.log(`Table event: The address of new selection is: ${args.address}`);
- });
- }
-
- async function onWorksheetSelectionChange(args: Excel.WorksheetSelectionChangedEventArgs) {
- await Excel.run(async (context) => {
- console.log(`Worksheet event: The address of new selection is: ${args.address}`);
- });
- }
-
- async function onWorksheetCollectionSelectionChange(args: Excel.WorksheetSelectionChangedEventArgs) {
- await Excel.run(async (context) => {
- console.log(`WorksheetCollection event: The address of new selection is: ${args.address}`);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- // Highlight an area and create a binding there.
- let bindingRange = sheet.getRange("A15:D20");
- bindingRange.format.fill.color = "yellow";
- sheet.getRange("A15").values = [["Binding range"]];
- context.workbook.bindings.add(bindingRange, Excel.BindingType.range, "YellowBinding");
-
- // Create a table.
- let salesTable = sheet.tables.add("A1:E1", true);
- salesTable.name = "SalesTable";
-
- salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- salesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |+
-
-
This sample shows how to register and use event handlers for table onChanged and onSelectionChanged events.
-
-
-
-
Set up
-
-
-
The onSelectionChanged events being listened for are:
-
-
Binding
-
Table
-
Worksheet
-
WorksheetCollection
-
-
-
-
-
Try it out
-
-
-
-
The console will log the addresses reported by the different onSelectionChanged events. Change the cell or cells selected in the worksheet to see the results. Try selecting single cells, multiple cells, and multiple discontiguous cells.
This sample shows how to filter PivotTables and manipulate their data.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
Change functions
-
-
-
-
-
-
-
-
-
Filtering
-
- After pressing the "Enable filter" button, manually select the classification filter for the PivotTable
-
-
-
Data Manipulation
-
-
-
-
-
Clean up
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/38-pivottable/pivottable-get-pivottables.yaml b/samples/excel/38-pivottable/pivottable-get-pivottables.yaml
deleted file mode 100644
index 23ac8032e..000000000
--- a/samples/excel/38-pivottable/pivottable-get-pivottables.yaml
+++ /dev/null
@@ -1,199 +0,0 @@
-order: 4
-id: excel-pivottables-get-pivottables
-name: Get PivotTables
-description: Get existing PivotTables in the workbook through their collections and through the ranges they occupy.
-host: EXCEL
-api_set:
- ExcelAPI: '1.12'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#get-pivottables-in-workbook").click(() => tryCatch(getPivotTablesInWorkbook));
- $("#get-pivottables-in-worksheet").click(() => tryCatch(getPivotTablesInWorksheet));
- $("#get-pivottables-in-selected-range").click(() => tryCatch(getPivotTablesInSelectedRange));
-
- async function getPivotTablesInWorkbook() {
- await Excel.run(async (context) => {
- // Get the names of all the PivotTables in the workbook.
- const pivotTables = context.workbook.pivotTables;
- pivotTables.load("name");
- await context.sync();
-
- // Display the names in the console.
- console.log("PivotTables in the workbook:")
- pivotTables.items.forEach((pivotTable) => {
- console.log(`\t${pivotTable.name}`);
- });
- });
- }
-
- async function getPivotTablesInWorksheet() {
- await Excel.run(async (context) => {
- // Get the names of all the PivotTables in the current worksheet.
- const pivotTables = context.workbook.worksheets.getActiveWorksheet().pivotTables;
- pivotTables.load("name");
- await context.sync();
-
- // Display the names in the console.
- console.log("PivotTables in the current worksheet:")
- pivotTables.items.forEach((pivotTable) => {
- console.log(`\t${pivotTable.name}`);
- });
- });
- }
-
- async function getPivotTablesInSelectedRange() {
- await Excel.run(async (context) => {
- const activeRange = context.workbook.getSelectedRange();
-
- // Get all the PivotTables that intersect with this range.
- const partiallyContainedPivotTables = activeRange.getPivotTables();
- // Get all the PivotTables that are completely contained within this range.
- const fullyContainedPivotTables = activeRange.getPivotTables(true);
-
- partiallyContainedPivotTables.load("name");
- fullyContainedPivotTables.load("name");
- await context.sync();
-
- // Display the names in the console.
- console.log("PivotTables in the current range:")
- partiallyContainedPivotTables.items.forEach((pivotTable) => {
- console.log(`\t${pivotTable.name}`);
- });
- console.log("PivotTables completely contained in the current range:")
- fullyContainedPivotTables.items.forEach((pivotTable) => {
- console.log(`\t${pivotTable.name}`);
- });
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create the worksheets.
- context.workbook.worksheets.getItemOrNullObject("Data").delete();
- const dataSheet = context.workbook.worksheets.add("Data");
- context.workbook.worksheets.getItemOrNullObject("TotalPivot").delete();
- context.workbook.worksheets.getItemOrNullObject("FilteredPivot").delete();
- const totalPivot = context.workbook.worksheets.add("TotalPivot");
- const filteredPivot = context.workbook.worksheets.add("FilteredPivot");
-
- // Create farm data.
- const data = [
- ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"],
- ["A Farms", "Lime", "Organic", 300, 2000],
- ["A Farms", "Lemon", "Organic", 250, 1800],
- ["A Farms", "Orange", "Organic", 200, 2200],
- ["B Farms", "Lime", "Conventional", 80, 1000],
- ["B Farms", "Lemon", "Conventional", 75, 1230],
- ["B Farms", "Orange", "Conventional", 25, 800],
- ["B Farms", "Orange", "Organic", 20, 500],
- ["B Farms", "Lemon", "Organic", 10, 770],
- ["B Farms", "Kiwi", "Conventional", 30, 300],
- ["B Farms", "Lime", "Organic", 50, 400],
- ["C Farms", "Apple", "Organic", 275, 220],
- ["C Farms", "Kiwi", "Organic", 200, 120],
- ["D Farms", "Apple", "Conventional", 100, 3000],
- ["D Farms", "Apple", "Organic", 80, 2800],
- ["E Farms", "Lime", "Conventional", 160, 2700],
- ["E Farms", "Orange", "Conventional", 180, 2000],
- ["E Farms", "Apple", "Conventional", 245, 2200],
- ["E Farms", "Kiwi", "Conventional", 200, 1500],
- ["F Farms", "Kiwi", "Organic", 100, 150],
- ["F Farms", "Lemon", "Conventional", 150, 270]
- ];
-
- const range = dataSheet.getRange("A1:E21");
- range.values = data;
- range.format.autofitColumns();
-
- // Create the first PivotTable.
- const pivotTable = totalPivot.pivotTables.add("All Farm Sales", "Data!A1:E21", "TotalPivot!A2");
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm"));
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm"));
-
- // Create the second PivotTable.
- const pivotTable2 = filteredPivot.pivotTables.add("Filtered Wholesale", "Data!A1:E21", "FilteredPivot!A2");
- pivotTable2.rowHierarchies.add(pivotTable2.hierarchies.getItem("Farm"));
- pivotTable2.rowHierarchies.add(pivotTable2.hierarchies.getItem("Type"));
- pivotTable2.dataHierarchies.add(pivotTable2.hierarchies.getItem("Crates Sold Wholesale"));
- pivotTable2.filterHierarchies.add(pivotTable2.hierarchies.getItem("Classification"));
-
- // Switch to one of the worksheets with a PivotTable.
- totalPivot.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to get PivotTables in the workbook. You can get them through PivotTableCollection objects
- or by querying a Range object containing PivotTable data.
-
-
-
-
Set up
-
This creates a data sheet and two PivotTables in two different worksheets.
-
-
-
-
-
Try it out
-
-
-
-
-
-
-
-
-
Note that this button only works with a single selected range.
- Multi-range selections aren't supported by `getPivotTables` at this time.
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/38-pivottable/pivottable-pivotfilters.yaml b/samples/excel/38-pivottable/pivottable-pivotfilters.yaml
deleted file mode 100644
index d07c74f5e..000000000
--- a/samples/excel/38-pivottable/pivottable-pivotfilters.yaml
+++ /dev/null
@@ -1,328 +0,0 @@
-order: 5
-id: excel-pivottables-pivotfilters
-name: PivotFilters
-description: Applies PivotFilters to a PivotTable.
-host: EXCEL
-api_set:
- ExcelAPI: '1.12'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#manual-filter").click(() => tryCatch(manualFilter));
- $("#date-filter").click(() => tryCatch(dateFilter));
- $("#value-filter").click(() => tryCatch(valueFilter));
- $("#label-filter").click(() => tryCatch(labelFilter));
- $("#clear-filters").click(() => tryCatch(clearFilters));
- $("#log-filters").click(() => tryCatch(logFilters));
- $("#get-crate-total").click(() => tryCatch(getCrateTotal));
-
- async function manualFilter() {
- await Excel.run(async (context) => {
- // Add a PivotFilter to filter on manually-selected items.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
-
- // PivotFilters can only be applied to PivotHierarchies that are being used for pivoting.
- // If it's not already there, add "Classification" to the hierarchies.
- let classHierarchy = pivotTable.filterHierarchies.getItemOrNullObject("Classification");
- await context.sync();
- if (classHierarchy.isNullObject) {
- classHierarchy = pivotTable.filterHierarchies.add(pivotTable.hierarchies.getItem("Classification"));
- }
-
- // Apply a manual filter to include only a specific PivotItem (the string "Organic").
- const filterField = classHierarchy.fields.getItem("Classification");
- const manualFilter = { selectedItems: ["Organic"]};
- filterField.applyFilter({ manualFilter: manualFilter });
-
- await context.sync();
- });
- }
-
- async function dateFilter() {
- await Excel.run(async (context) => {
- // Add a date-based PivotFilter.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
-
- // PivotFilters can only be applied to PivotHierarchies that are being used for pivoting.
- // If it's not already there, add "Date Updated" to the hierarchies.
- let dateHierarchy = pivotTable.rowHierarchies.getItemOrNullObject("Date Updated");
- await context.sync();
- if (dateHierarchy.isNullObject) {
- dateHierarchy = pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Date Updated"));
- }
-
- // Apply a date filter to filter out anything logged before August.
- const filterField = dateHierarchy.fields.getItem("Date Updated");
- const dateFilter = {
- condition: Excel.DateFilterCondition.afterOrEqualTo,
- comparator: {
- date: "2020-08-01",
- specificity: Excel.FilterDatetimeSpecificity.month
- }
- };
- filterField.applyFilter({ dateFilter: dateFilter });
-
- await context.sync();
- });
- }
-
- async function valueFilter() {
- await Excel.run(async (context) => {
- // Add a PivotFilter to filter on the values correlated with a row.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
-
- // Get the "Farm" field.
- const field = pivotTable.hierarchies.getItem("Farm").fields.getItem("Farm");
-
- // Filter to only include rows with more than 500 wholesale crates sold.
- const filter: Excel.PivotValueFilter = {
- condition: Excel.ValueFilterCondition.greaterThan,
- comparator: 500,
- value: "Sum of Crates Sold Wholesale"
- };
-
- // Apply the value filter to the field.
- field.applyFilter({ valueFilter: filter });
-
- await context.sync();
- });
- }
-
- async function labelFilter() {
- await Excel.run(async (context) => {
- // Add a PivotFilter to filter based on the strings of item labels.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
-
- // Get the "Type" field.
- const field = pivotTable.hierarchies.getItem("Type").fields.getItem("Type");
-
- // Filter out any types that start with "L" ("Lemons" and "Limes" in this case).
- const filter: Excel.PivotLabelFilter = {
- condition: Excel.LabelFilterCondition.beginsWith,
- substring: "L",
- exclusive: true
- };
-
- // Apply the label filter to the field.
- field.applyFilter({ labelFilter: filter });
-
- await context.sync();
- });
- }
-
- async function clearFilters() {
- await Excel.run(async (context) => {
- // Clear all the PivotFilters.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
- pivotTable.hierarchies.load("name");
- await context.sync();
-
- // Clear the filters on each PivotField.
- pivotTable.hierarchies.items.forEach((hierarchy) => {
- hierarchy.fields.getItem(hierarchy.name).clearAllFilters();
- });
- await context.sync();
- });
- }
-
- async function getCrateTotal() {
- await Excel.run(async (context) => {
- // Get the total amounts from the PivotTable.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
-
- // The layout controls the ranges used by the PivotTable.
- const range = pivotTable.layout.getDataBodyRange();
-
- // Get all the data hierarchy totals.
- const grandTotalRange = range.getLastRow();
- grandTotalRange.load("address");
-
- // Use the wholesale and farm sale totals to make a final sum.
- const sumResult = context.workbook.functions.sum(grandTotalRange);
- sumResult.load("value");
- await context.sync();
-
- console.log(`Total crate count: ${sumResult.value}`);
- await context.sync();
- });
- }
-
- async function logFilters() {
- await Excel.run(async (context) => {
- // Display all the active PivotFilters.
-
- // Get the PivotTable.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
-
- // Get the number of PivotHierarchies.
- pivotTable.hierarchies.load("name");
- let hierarchyCount = pivotTable.hierarchies.getCount();
- await context.sync();
-
- // Iterate over all the hierarchies looking for filters on the PivotFields.
- for (let i = 0; i < hierarchyCount.value; i++) {
- let filters = pivotTable.hierarchies.items[i].fields.getItem(pivotTable.hierarchies.items[i].name).getFilters();
- await context.sync();
-
- if (
- filters.value.dateFilter ||
- filters.value.labelFilter ||
- filters.value.manualFilter ||
- filters.value.valueFilter
- ) {
- console.log(`Filters found on "${pivotTable.hierarchies.items[i].name}" field:`);
- console.log(filters.value);
- }
- }
-
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create the worksheets.
- context.workbook.worksheets.getItemOrNullObject("Data").delete();
- const dataSheet = context.workbook.worksheets.add("Data");
- context.workbook.worksheets.getItemOrNullObject("Pivot").delete();
- const pivotSheet = context.workbook.worksheets.add("Pivot");
-
- // Create farm data.
- const data = [
- ["Farm", "Type", "Classification", "Date Updated", "Crates Sold at Farm", "Crates Sold Wholesale"],
- ["A Farms", "Lime", "Organic", "8/12/2020", 300, 2000],
- ["A Farms", "Lemon", "Organic", "8/11/2020", 250, 1800],
- ["A Farms", "Orange", "Organic", "8/1/2020", 200, 2200],
- ["B Farms", "Lime", "Conventional", "8/2/2020", 80, 1000],
- ["B Farms", "Lemon", "Conventional", "7/29/2020", 75, 1230],
- ["B Farms", "Orange", "Conventional", "7/15/2020", 25, 800],
- ["B Farms", "Orange", "Organic", "8/1/2020", 20, 500],
- ["B Farms", "Lemon", "Organic", "8/5/2020", 10, 770],
- ["B Farms", "Kiwi", "Conventional", "7/25/2020", 30, 300],
- ["B Farms", "Lime", "Organic", "7/15/2020", 50, 600],
- ["C Farms", "Apple", "Organic", "8/1/2020", 275, 220],
- ["C Farms", "Kiwi", "Organic", "8/1/2020", 200, 120],
- ["D Farms", "Apple", "Conventional", "7/23/2020", 100, 3000],
- ["D Farms", "Apple", "Organic", "7/26/2020", 80, 2800],
- ["E Farms", "Lime", "Conventional", "8/1/2020", 160, 2700],
- ["E Farms", "Orange", "Conventional", "8/7/2020", 180, 2000],
- ["E Farms", "Apple", "Conventional", "8/10/2020", 245, 2200],
- ["E Farms", "Kiwi", "Conventional", "8/11/2020", 200, 1500],
- ["F Farms", "Kiwi", "Organic", "7/30/2020", 100, 150],
- ["F Farms", "Lemon", "Conventional", "7/14/2020", 150, 270]
- ];
-
- const range = dataSheet.getRange("A1:F21");
- range.values = data;
- range.format.autofitColumns();
- pivotSheet.activate();
-
- // Create the PivotTable.
- context.workbook.worksheets.getActiveWorksheet().pivotTables.add("Farm Sales", "Data!A1:F21", "A2");
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm"));
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale"));
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to filter PivotTables with the different PivotFilters.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
Filters
-
Manual filter
-
-
-
Date filter
-
-
-
Value filter
-
-
-
Label filter
-
-
-
PivotTable Status
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
diff --git a/samples/excel/38-pivottable/pivottable-pivotlayout.yaml b/samples/excel/38-pivottable/pivottable-pivotlayout.yaml
deleted file mode 100644
index acbd8c3f0..000000000
--- a/samples/excel/38-pivottable/pivottable-pivotlayout.yaml
+++ /dev/null
@@ -1,323 +0,0 @@
-order: 6
-id: excel-pivottable-pivotlayout
-name: PivotLayout
-description: Sets PivotTable layout settings through the PivotLayout.
-host: EXCEL
-api_set:
- ExcelAPI: '1.13'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#change-layout").click(() => tryCatch(changeLayout));
- $("#add-alt-text").click(() => tryCatch(addAltText));
- $("#add-line-spacing").click(() => tryCatch(addLineSpacing));
- $("#repeat-item-labels").click(() => tryCatch(repeatItemLabels));
- $("#toggle-field-headers").click(() => tryCatch(toggleFieldHeaders));
- $("#toggle-grand-totals").click(() => tryCatch(toggleGrandTotals));
- $("#set-empty-cell-text").click(() => tryCatch(setEmptyCellText));
- $("#toggle-fill-empty-cells").click(() => tryCatch(toggleFillEmptyCells));
- $("#toggle-auto-format").click(() => tryCatch(toggleAutoFormat));
- $("#toggle-preserve-formatting").click(() => tryCatch(togglePreserveFormatting));
-
- async function changeLayout() {
- await Excel.run(async (context) => {
- // Change the PivotLayout.type to a new type.
- const pivotTable = context.workbook.worksheets.getActiveWorksheet().pivotTables.getItem("Farm Sales");
- pivotTable.layout.load("layoutType");
- await context.sync();
-
- // Cycle between the three layout types.
- if (pivotTable.layout.layoutType === "Compact") {
- pivotTable.layout.layoutType = "Outline";
- } else if (pivotTable.layout.layoutType === "Outline") {
- pivotTable.layout.layoutType = "Tabular";
- } else {
- pivotTable.layout.layoutType = "Compact";
- }
-
- await context.sync();
- console.log("Pivot layout is now " + pivotTable.layout.layoutType);
- });
- }
-
- async function addAltText() {
- await Excel.run(async (context) => {
- // Set the alt text for the displayed PivotTable.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.altTextTitle = "Farm Sales PivotTable";
- pivotLayout.altTextDescription = "A summary of fruit sales. It is pivoted on farm name, and fruit type. The aggregated data is both the sums of crates sold at the farms and the sums of crates sold wholesale.";
- console.log("Adding alt text. Check the PivotTable settings to see the changes.");
-
- await context.sync();
- });
- }
-
- async function addLineSpacing() {
- await Excel.run(async (context) => {
- // Add a blank row after each PivotItem in the row hierarchy.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.displayBlankLineAfterEachItem(true);
- console.log("Setting `PivotLayout.displayBlankLineAfterEachItem` to true.");
-
- await context.sync();
- });
- }
-
- async function repeatItemLabels() {
- await Excel.run(async (context) => {
- // Repeat the PivotItem labels for each row used by another level of the row hierarchy.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.repeatAllItemLabels(true);
- console.log("Setting `PivotLayout.repeatAllItemLabels` to true.");
-
- await context.sync();
- });
- }
-
- async function toggleFieldHeaders() {
- await Excel.run(async (context) => {
- // Turn the field headers on and off for the row and column hierarchies.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
- pivotLayout.load("showFieldHeaders");
- await context.sync();
-
- let showHeaders = !pivotLayout.showFieldHeaders;
- console.log(`Show field headers? - ${showHeaders}`);
- pivotLayout.showFieldHeaders = showHeaders;
- await context.sync();
- });
- }
-
- async function toggleGrandTotals() {
- await Excel.run(async (context) => {
- // Turn the grand totals on and off for the rows and columns.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.load(["showRowGrandTotals", "showColumnGrandTotals"]);
- await context.sync();
-
- let showColumnTotals = !pivotLayout.showColumnGrandTotals;
- let showRowTotals = !pivotLayout.showRowGrandTotals;
- console.log(`Show column grand totals? - ${showColumnTotals}`);
- console.log(`Show row grand totals? - ${showRowTotals}`);
-
- pivotLayout.showColumnGrandTotals = showColumnTotals;
- pivotLayout.showRowGrandTotals = showRowTotals;
-
- await context.sync();
- });
- }
-
- async function setEmptyCellText() {
- await Excel.run(async (context) => {
- // Set a default value for an empty cell in the PivotTable. This doesn't include cells left blank by the layout.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.emptyCellText = "--";
-
- // Set the text alignment to match the rest of the PivotTable.
- pivotLayout.getDataBodyRange().format.horizontalAlignment = Excel.HorizontalAlignment.right;
- await context.sync();
- });
- }
-
- async function toggleFillEmptyCells() {
- await Excel.run(async (context) => {
- // Toggle whether empty cells are filled with a default value.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.load("fillEmptyCells");
- await context.sync();
-
- let fillToSet = !pivotLayout.fillEmptyCells;
- console.log(`Filling empty cells? - ${fillToSet}`);
-
- pivotLayout.fillEmptyCells = fillToSet;
- await context.sync();
- });
- }
-
- async function toggleAutoFormat() {
- await Excel.run(async (context) => {
- // Set whether the PivotTable adjusts the format after it is refreshed and recalculated.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.load("autoFormat");
- await context.sync();
-
- let autoFormatToSet = !pivotLayout.autoFormat;
- console.log(`Automatically format PivotTable after a refresh? - ${autoFormatToSet}`);
-
- pivotLayout.autoFormat = autoFormatToSet;
- await context.sync();
- });
- }
-
- async function togglePreserveFormatting() {
- await Excel.run(async (context) => {
- // Set whether the PivotTable keeps the established format after it is refreshed and recalculated.
- const pivotTable = context.workbook.pivotTables.getItem("Farm Sales");
- const pivotLayout = pivotTable.layout;
-
- pivotLayout.load("preserveFormatting");
- await context.sync();
-
- let preserveFormattingToSet = !pivotLayout.preserveFormatting;
- console.log(`Preserve the formatting PivotTable after a refresh? - ${preserveFormattingToSet}`);
-
- pivotLayout.preserveFormatting = preserveFormattingToSet;
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Data").delete();
- const dataSheet = context.workbook.worksheets.add("Data");
- context.workbook.worksheets.getItemOrNullObject("Pivot").delete();
- const pivotSheet = context.workbook.worksheets.add("Pivot");
-
- const data = [
- ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"],
- ["A Farms", "Lime", "Organic", 300, 2000],
- ["A Farms", "Lemon", "Organic", 250, 1800],
- ["A Farms", "Orange", "Organic", "", 2200],
- ["B Farms", "Lime", "Conventional", 80, 1000],
- ["B Farms", "Lemon", "Conventional", "", 1230],
- ["B Farms", "Orange", "Conventional", 25, 800],
- ["B Farms", "Orange", "Organic", 20, 500],
- ["B Farms", "Lemon", "Organic", "", 770],
- ["B Farms", "Kiwi", "Conventional", 30, 300],
- ["B Farms", "Lime", "Organic", "", 400],
- ["C Farms", "Apple", "Organic", 275, 220],
- ["C Farms", "Kiwi", "Organic", 200, 120],
- ["D Farms", "Apple", "Conventional", 100, ""],
- ["D Farms", "Apple", "Organic", 80, 2800],
- ["E Farms", "Lime", "Conventional", 160, 2700],
- ["E Farms", "Orange", "Conventional", "", 2000],
- ["E Farms", "Apple", "Conventional", 245, 2200],
- ["E Farms", "Kiwi", "Conventional", 200, ""],
- ["F Farms", "Kiwi", "Organic", 100, ""],
- ["F Farms", "Lemon", "Conventional", "", 270]
- ];
-
- const range = dataSheet.getRange("A1:E21");
- range.values = data;
- range.format.autofitColumns();
-
- pivotSheet.activate();
-
- const rangeToAnalyze = context.workbook.worksheets.getItem("Data").getRange("A1:E21");
- const rangeToPlacePivot = context.workbook.worksheets.getItem("Pivot").getRange("A2");
- const pivotTable = context.workbook.worksheets
- .getItem("Pivot")
- .pivotTables.add("Farm Sales", rangeToAnalyze, rangeToPlacePivot);
-
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm"));
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type"));
-
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale"));
-
- // Add the following if you'd like to see how the layout settings affect a column hierarchy.
- //pivotTable.columnHierarchies.add(pivotTable.hierarchies.getItem("Classification"));
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to work with the PivotLayout class to display the PivotTable.
This sample shows how to work with a slicer on a PivotTable.
-
-
-
-
Setup
-
-
-
-
-
-
Try it out
-
Add the slicer, then try out the formatting and filtering options.
-
-
-
Formatting
-
-
-
-
-
Data
-
-
-
-
-
Clean up
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/38-pivottable/pivottable-source-data.yaml b/samples/excel/38-pivottable/pivottable-source-data.yaml
deleted file mode 100644
index e0ceb5821..000000000
--- a/samples/excel/38-pivottable/pivottable-source-data.yaml
+++ /dev/null
@@ -1,135 +0,0 @@
-order: 7
-id: excel-pivottable-data-source
-name: PivotTable data source
-description: Gets information about the data source of a PivotTable.
-host: EXCEL
-api_set:
- ExcelApi: '1.15'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#get-pivottable-data-source").click(() => tryCatch(getPivotTableDataSource));
-
- async function getPivotTableDataSource() {
- // This function logs information about the data source of a PivotTable.
- await Excel.run(async (context) => {
- const worksheet = context.workbook.worksheets.getItem("TotalPivot");
- const pivotTable = worksheet.pivotTables.getItem("All Farm Sales");
-
- // Retrieve the type and string representation of the data source of the PivotTable.
- const pivotTableDataSourceType = pivotTable.getDataSourceType();
- const pivotTableDataSourceString = pivotTable.getDataSourceString();
- await context.sync();
-
- // Log the data source information.
- console.log("Data source: " + pivotTableDataSourceString.value);
- console.log("Source type: " + pivotTableDataSourceType.value);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- // Create the worksheets.
- context.workbook.worksheets.getItemOrNullObject("Data").delete();
- const dataSheet = context.workbook.worksheets.add("Data");
- context.workbook.worksheets.getItemOrNullObject("TotalPivot").delete();
- const totalPivot = context.workbook.worksheets.add("TotalPivot");
-
- // Create farm data.
- const data = [
- ["Farm", "Type", "Classification", "Crates Sold at Farm", "Crates Sold Wholesale"],
- ["A Farms", "Lime", "Organic", 300, 2000],
- ["A Farms", "Lemon", "Organic", 250, 1800],
- ["A Farms", "Orange", "Organic", 200, 2200],
- ["B Farms", "Lime", "Conventional", 80, 1000],
- ["B Farms", "Lemon", "Conventional", 75, 1230],
- ["B Farms", "Orange", "Conventional", 25, 800],
- ["B Farms", "Orange", "Organic", 20, 500],
- ["B Farms", "Lemon", "Organic", 10, 770],
- ["B Farms", "Kiwi", "Conventional", 30, 300],
- ["B Farms", "Lime", "Organic", 50, 400],
- ["C Farms", "Apple", "Organic", 275, 220],
- ["C Farms", "Kiwi", "Organic", 200, 120],
- ["D Farms", "Apple", "Conventional", 100, 3000],
- ["D Farms", "Apple", "Organic", 80, 2800],
- ["E Farms", "Lime", "Conventional", 160, 2700],
- ["E Farms", "Orange", "Conventional", 180, 2000],
- ["E Farms", "Apple", "Conventional", 245, 2200],
- ["E Farms", "Kiwi", "Conventional", 200, 1500],
- ["F Farms", "Kiwi", "Organic", 100, 150],
- ["F Farms", "Lemon", "Conventional", 150, 270]
- ];
-
- const range = dataSheet.getRange("A1:E21");
- range.values = data;
- range.format.autofitColumns();
-
- // Create the PivotTable.
- const pivotTable = totalPivot.pivotTables.add("All Farm Sales", "Data!A1:E21", "TotalPivot!A2");
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Farm"));
- pivotTable.rowHierarchies.add(pivotTable.hierarchies.getItem("Type"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold Wholesale"));
- pivotTable.dataHierarchies.add(pivotTable.hierarchies.getItem("Crates Sold at Farm"));
-
- // Switch to the worksheet with a PivotTable.
- totalPivot.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */ async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to get information about the data source of a PivotTable. It returns the type and string representation of the data source.
-
Note: This sample works in Excel on Windows and Excel on the web. It doesn't work in Excel on Mac; this is a known issue.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/cell-properties.yaml b/samples/excel/42-range/cell-properties.yaml
deleted file mode 100644
index e923d3f2d..000000000
--- a/samples/excel/42-range/cell-properties.yaml
+++ /dev/null
@@ -1,194 +0,0 @@
-order: 6
-id: excel-range-cell-properties
-name: Get and set cell properties
-description: Sets different properties across a range then retrieves those properties.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.9'
-script:
- content: |
- $("#set-cell-properties").click(() => tryCatch(setCellProperties));
- $("#get-cell-properties").click(() => tryCatch(getCellProperties));
- $("#setup").click(() => tryCatch(setup));
-
- async function setCellProperties() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Creating the SettableCellProperties objects to use for the range.
- // In your add-in, these should be created once, outside the function.
- const topHeaderProps: Excel.SettableCellProperties = {
- // The style property takes a string matching the name of an Excel style.
- // Built-in style names are listed in the `BuiltInStyle` enum.
- // Note that a style will overwrite any formatting,
- // so do not use the format property with the style property.
- style: "Heading1"
- };
-
- const headerProps: Excel.SettableCellProperties = {
- // Any subproperties of format that are not set will not be changed when these cell properties are set.
- format: {
- fill: {
- color: "Blue"
- },
- font: {
- color: "White",
- bold: true
- }
- }
- };
-
- const nonApplicableProps: Excel.SettableCellProperties = {
- format: {
- fill: {
- pattern: Excel.FillPattern.gray25
- },
- font: {
- color: "Gray",
- italic: true
- }
- }
- };
-
- const matchupScoreProps: Excel.SettableCellProperties = {
- format: {
- borders: {
- bottom: {
- style: Excel.BorderLineStyle.continuous
- },
- left: {
- style: Excel.BorderLineStyle.continuous
- },
- right: {
- style: Excel.BorderLineStyle.continuous
- },
- top: {
- style: Excel.BorderLineStyle.continuous
- }
- }
- }
- };
-
- const range = sheet.getRange("A1:E5");
-
- // You can use empty JSON objects to avoid changing a cell's properties.
- range.setCellProperties([
- [topHeaderProps, {}, {}, {}, {}],
- [{}, {}, headerProps, headerProps, headerProps],
- [{}, headerProps, nonApplicableProps, matchupScoreProps, matchupScoreProps],
- [{}, headerProps, matchupScoreProps, nonApplicableProps, matchupScoreProps],
- [{}, headerProps, matchupScoreProps, matchupScoreProps, nonApplicableProps]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- await context.sync();
- });
- }
-
- async function getCellProperties() {
- await Excel.run(async (context) => {
- const cell = context.workbook.getActiveCell();
-
- // Define the cell properties to get by setting the matching LoadOptions to true.
- const propertiesToGet = cell.getCellProperties({
- address: true,
- format: {
- fill: {
- color: true
- },
- font: {
- color: true
- }
- },
- style: true
- });
-
- // Sync to get the data from the workbook.
- await context.sync();
- const cellProperties = propertiesToGet.value[0][0];
- console.log(
- `Address: ${cellProperties.address}\nStyle: ${cellProperties.style}\nFill Color: ${cellProperties.format.fill.color}\nFont Color: ${cellProperties.format.font.color}`);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const data = [
- ["Matchups", " ", " ", " ", " "],
- [" ", " ", "SEA", "POR", "VAN"],
- [" ", "SEA", "N/A", -1, 2],
- [" ", "POR", 1, "N/A", 4],
- [" ", "VAN", -2, -4, "N/A"]
- ];
-
- const range = sheet.getRange("A1:E5");
- range.values = data;
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to format a range.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
Select a cell and press the following button to display some of the cell properties.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/dynamic-arrays.yaml b/samples/excel/42-range/dynamic-arrays.yaml
deleted file mode 100644
index 8411cc596..000000000
--- a/samples/excel/42-range/dynamic-arrays.yaml
+++ /dev/null
@@ -1,185 +0,0 @@
-order: 16
-id: excel-range-dynamic-arrays
-name: Dynamic arrays
-description: Applies formulas that use dynamic arrays and displays information about the ranges used to display the data.
-host: EXCEL
-api_set:
- ExcelAPI: '1.12'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#copy-table-headers").click(() => tryCatch(copyTableHeaders));
- $("#apply-filter-function").click(() => tryCatch(applyFilterFunction));
- $("#display-spill-information").click(() => tryCatch(displaySpillInformation));
-
- async function copyTableHeaders() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
-
- // Set G4 to a formula that returns a dynamic array.
- const targetCell = sheet.getRange("G4");
- targetCell.formulas = [["=A4:D4"]];
-
- // Get the address of the cells that the dynamic array spilled into.
- const spillRange = targetCell.getSpillingToRange();
- spillRange.load("address");
-
- // Fit the columns for readability.
- sheet.getUsedRange().format.autofitColumns();
- await context.sync();
-
- console.log(`Copying the table headers spilled into ${spillRange.address}.`);
- });
- }
-
- async function applyFilterFunction() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
-
- /* Set G5 to a formula that returns a dynamic array.
- * The FILTER formula filters the data in A5:D11 based on the values in the "C" column.
- * The parameter for the filter is "H2".
- */
- const targetCell = sheet.getRange("G5");
- targetCell.formulas = [['=FILTER(A5:D11,C5:C11=H2,"")']];
-
- // Get the address of the cells that the dynamic array spilled into.
- const spillRange = targetCell.getSpillingToRange();
- spillRange.load("address");
-
- // Fit the columns for readability.
- sheet.getUsedRange().format.autofitColumns();
- await context.sync();
-
- console.log(`Applying the FILTER formula spilled into ${spillRange.address}.`);
- });
- }
-
- async function displaySpillInformation() {
- await Excel.run(async (context) => {
- // Check the current cell for any spill parents or spilling-to ranges.
- const currentRange = context.workbook.getSelectedRange();
-
- // Spill parent shows the ranges that are causing data to spill into the current cell.
- const spillParent = currentRange.getSpillParentOrNullObject();
- spillParent.load("address");
-
- // Spilling-to range shows the ranges to which this cell is applying the results of a dynamic array.
- const spillRange = currentRange.getSpillingToRangeOrNullObject();
- spillRange.load("address");
- await context.sync();
-
- // Log the dynamic array information contained within the selected cell.
- if (!spillParent.isNullObject) {
- console.log(`The selected cell has a spill parent at ${spillParent.address}`);
- }
- if (!spillRange.isNullObject) {
- console.log(`The selected cell is spilling into ${spillRange.address}`);
- }
-
- if (spillParent.isNullObject && spillRange.isNullObject) {
- console.log("The selected cell is not involved with any dynamic arrays (or you have multiple cells selected).");
- }
- });
- }
-
- /** Create a new table with sample data */
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const expensesTable = sheet.tables.add("A4:D4", true /*hasHeaders*/);
- expensesTable.name = "ExpensesTable";
-
- expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]];
-
- expensesTable.rows.add(null /*add at the end*/, [
- ["1/1/2020", "The Phone Company", "Communications", "$120"],
- ["1/2/2020", "Northwind Electric Cars", "Transportation", "$142"],
- ["1/5/2020", "Best For You Organics Company", "Groceries", "$27"],
- ["1/10/2020", "Coho Vineyard", "Restaurant", "$33"],
- ["1/11/2020", "Bellows College", "Education", "$350"],
- ["1/15/2020", "Trey Research", "Other", "$135"],
- ["1/15/2020", "Best For You Organics Company", "Groceries", "$97"]
- ]);
-
- sheet.getRange("A2:H2").values = [["Transactions", , , , , , "Category", "Groceries"]];
- sheet.getRange("A2").style = "Heading1";
- sheet.getRange("G2").style = "Heading2";
- sheet.getRange("H2").format.fill.color = "#EEEE99";
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to apply formulas that return dynamic arrays and how to get the relevant information
- about range spilling from the used ranges.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
Select a spilled cell and press the following button to see information for that cell related to dynamic
- arrays.
This sample shows how to insert, delete and clear the contents of a range.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/outline.yaml b/samples/excel/42-range/outline.yaml
deleted file mode 100644
index 02f043b4a..000000000
--- a/samples/excel/42-range/outline.yaml
+++ /dev/null
@@ -1,240 +0,0 @@
-order: 9
-id: excel-outline
-name: Outline
-description: Creates an outline by grouping rows and columns.
-host: EXCEL
-api_set:
- ExcelApi: '1.10'
-script:
- content: |
- $("#setup-data").click(() => tryCatch(setupData));
- $("#setup-totals").click(() => tryCatch(setupTotals));
- $("#group-rows").click(() => tryCatch(groupRows));
- $("#group-columns").click(() => tryCatch(groupColumns));
- $("#collapse-outline").click(() => tryCatch(collapseOutline));
- $("#expand-outline").click(() => tryCatch(expandOutline));
- $("#ungroup").click(() => tryCatch(ungroup));
-
- async function groupRows() {
- Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Group the larger, main level. Note that the outline controls
- // will be on row 10, meaning 4-9 will collapse and expand.
- sheet.getRange("4:9").group(Excel.GroupOption.byRows);
-
- // Group the smaller, sublevels. Note that the outline controls
- // will be on rows 6 and 9, meaning 4-5 and 7-8 will collapse and expand.
- sheet.getRange("4:5").group(Excel.GroupOption.byRows);
- sheet.getRange("7:8").group(Excel.GroupOption.byRows);
- await context.sync();
- });
- }
-
- async function groupColumns() {
- Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Group the larger, main level. Note that the outline controls
- // will be on column R, meaning C-Q will collapse and expand.
- sheet.getRange("C:Q").group(Excel.GroupOption.byColumns);
-
- // Group the smaller, sublevels. Note that the outline controls
- // will be on columns G, L, and R, meaning C-F, H-K, and M-P will collapse and expand.
- sheet.getRange("C:F").group(Excel.GroupOption.byColumns);
- sheet.getRange("H:K").group(Excel.GroupOption.byColumns);
- sheet.getRange("M:P").group(Excel.GroupOption.byColumns);
- await context.sync();
- });
- }
-
- async function collapseOutline() {
- Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // This collapses the entire outline.
- sheet.showOutlineLevels(1, 1);
- await context.sync();
- });
- }
-
- async function expandOutline() {
- Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // This shows the top 3 outline levels; collapsing any additional sublevels.
- sheet.showOutlineLevels(3, 3);
- await context.sync();
- });
- }
-
- async function ungroup() {
- Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // This removes two levels of groups from the "A1-R10" range.
- // Any groups at the same level on the same dimension will be removed by a single call.
- sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byRows);
- sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byRows);
- sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byColumns);
- sheet.getRange("A1:R10").ungroup(Excel.GroupOption.byColumns);
- await context.sync();
- });
- }
-
- async function setupData() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const data = [
- ["Category", "Type", "Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"],
- ["Stone Fruit", "Peaches", 500, 2000, 5000, 1500, 600, 2200, 5400, 1300, 300, 1500, 4300, 1200],
- [, "Plums", 700, 900, 1300, 800, 800, 1000, 2000, 700, 300, 600, 1100, 700],
- ["Citrus", "Lemons", 8000, 3000, 4500, 7500, 8900, 4000, 3500, 4500, 6000, 2500, 4500, 9500],
- [, "Limes", 12000, 7000, 8000, 13000, 16000, 10000, 8500, 12000, 11000, 5600, 6500, 11000]
- ];
-
- sheet.getRange("A3:N7").values = data;
- sheet.getRange("A1").values = [["Fruit Sales"]];
- sheet.getRange("A1").style = "Heading1";
- sheet.getRanges("C2:N3,A3:B7").format.font.bold = true;
-
- sheet.getRange("A1:N7").format.autofitColumns();
- sheet.activate();
-
- await context.sync();
- });
- }
-
- async function setupTotals() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const subtotalColumns = ["G", "L", "Q"];
- const subtotalRows = ["6", "9"];
- let year = 2017;
- for (let column of subtotalColumns) {
- sheet.getRange(`${column}:${column}`).insert(Excel.InsertShiftDirection.right);
- sheet.getRange(`${column}3`).values = [["Year Total"]];
- sheet.getRange(`${column}3`).getRowsAbove(1).values = [[`${year++}`]];
- }
-
- for (let row of subtotalRows) {
- sheet.getRange(`${row}:${row}`).insert(Excel.InsertShiftDirection.down);
- sheet.getRange(`B${row}`).values = [["Category Total"]];
- }
-
- for (let column of subtotalColumns) {
- const totalRange = sheet.getRange(`${column}4`);
- const precedingRange = totalRange.getColumnsBefore(4);
- precedingRange.load("address");
- await context.sync();
- totalRange.formulas = [[`=SUM(${precedingRange.address})`]];
- totalRange.format.font.italic = true;
- totalRange.format.fill.color = "LightBlue";
- totalRange.autoFill(`${column}4:${column}9`);
- }
-
- for (let row of subtotalRows) {
- const totalRange = sheet.getRange(`C${row}`);
- const precedingRange = totalRange.getRowsAbove(2);
- precedingRange.load("address");
- await context.sync();
- totalRange.formulas = [[`=SUM(${precedingRange.address})`]];
- totalRange.format.font.italic = true;
- totalRange.format.fill.color = "LightBlue";
- totalRange.autoFill(`C${row}:Q${row}`);
- }
-
- sheet.getRange("R3").values = [["Grand Total"]];
- sheet.getRange("R4").formulas = [["=SUM(G4,K4,Q4)"]];
- sheet.getRange("R4").autoFill("R4:R9");
-
- sheet.getRange("B10").values = [["Grand Total"]];
- sheet.getRange("C10").formulas = [["=SUM(C6,C9)"]];
- sheet.getRange("C10").autoFill("C10:R10");
-
- sheet.getRange("A1:R9").format.autofitColumns();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback, option?) {
- try {
- await callback(option);
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to group and ungroup rows and columns for an outline.
-
-
-
-
Set up
-
-
-
-
-
-
-
Try it out
-
-
-
-
-
Use the Excel UI to expand or collapse parts of the outline. The following buttons will expand or collapse the
- entire outline.
-
-
-
-
-
When you are finished exploring the grouping functionality, use the following button to ungroup the rows and
- columns.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/precedents.yaml b/samples/excel/42-range/precedents.yaml
deleted file mode 100644
index 26988d156..000000000
--- a/samples/excel/42-range/precedents.yaml
+++ /dev/null
@@ -1,215 +0,0 @@
-order: 13
-id: excel-precedents
-name: Precedents
-description: This sample shows how to find and highlight the precedents of the currently selected cell. Precedents are cells referenced by the formula in a cell.
-host: EXCEL
-api_set:
- ExcelApi: '1.14'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#select-first-cell").click(() => tryCatch(selectFirstCell));
- $("#select-second-cell").click(() => tryCatch(selectSecondCell));
- $("#get-direct-precedents").click(() => tryCatch(getDirectPrecedents));
- $("#get-all-precedents").click(() => tryCatch(getAllPrecedents));
- $("#clear-highlighting").click(() => tryCatch(clearFormatting));
-
- /** Select a cell with precedents on one worksheet. */
- async function selectFirstCell() {
- await Excel.run(async (context) => {
- // Ensure correct worksheet is active.
- const sheet = context.workbook.worksheets.getItem("Sample2020Data");
- sheet.activate();
-
- // Select cell E4.
- const range = sheet.getRange("E4");
- range.select();
- await context.sync();
- });
- }
-
- /** Select a cell with precedents on both worksheets. */
- async function selectSecondCell() {
- await Excel.run(async (context) => {
- // Ensure correct worksheet is active.
- const sheet = context.workbook.worksheets.getItem("Sample2020Data");
- sheet.activate();
-
- // Select cell F5.
- const range = sheet.getRange("F5");
- range.select();
- await context.sync();
- });
- }
-
- async function getDirectPrecedents() {
- await Excel.run(async (context) => {
- // Precedents are cells referenced by the formula in a cell.
- // A "direct precedent" is a cell directly referenced by the selected formula.
- let range = context.workbook.getActiveCell();
- let directPrecedents = range.getDirectPrecedents();
- range.load("address");
- directPrecedents.areas.load("address");
- await context.sync();
-
- console.log(`Direct precedent cells of ${range.address}:`);
-
- // Use the direct precedents API to loop through precedents of the active cell.
- for (let i = 0; i < directPrecedents.areas.items.length; i++) {
- // Highlight and console the address of each precedent cell.
- directPrecedents.areas.items[i].format.fill.color = "Yellow";
- console.log(` ${directPrecedents.areas.items[i].address}`);
- }
- await context.sync();
- });
- }
-
- async function getAllPrecedents() {
- await Excel.run(async (context) => {
- // Precedents are cells referenced by the formula in a cell.
- let range = context.workbook.getActiveCell();
- let precedents = range.getPrecedents();
- range.load("address");
- precedents.areas.load("address");
- await context.sync();
-
- console.log(`All precedent cells of ${range.address}:`);
-
- // Use the precedents API to loop through precedents of the active cell.
- for (let i = 0; i < precedents.areas.items.length; i++) {
- // Highlight and console the address of each precedent cell.
- precedents.areas.items[i].format.fill.color = "Orange";
- console.log(` ${precedents.areas.items[i].address}`);
- }
- await context.sync();
- });
- }
-
- /** Remove highlighting from precedent cells. */
- async function clearFormatting() {
- await Excel.run(async (context) => {
- const sheet1 = context.workbook.worksheets.getItem("Sample2019Data");
- let range1 = sheet1.getRange("B3:F5");
- range1.format.fill.clear();
-
- const sheet2 = context.workbook.worksheets.getItem("Sample2020Data");
- let range2 = sheet2.getRange("B3:E5");
- range2.format.fill.clear();
-
- await context.sync();
- });
- }
-
- /** Create two sample tables with methods that span the tables. */
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample2019Data").delete();
- context.workbook.worksheets.getItemOrNullObject("Sample2020Data").delete();
-
- // Set up the first sample table.
- const sheet1 = context.workbook.worksheets.add("Sample2019Data");
- const data1 = [
- ["Product", "Qty", "Unit Price", "Total Price 2019"],
- ["Almonds", 2, 7.5, "=C3 * D3"],
- ["Coffee", 1, 34.5, "=C4 * D4"],
- ["Chocolate", 5, 9.56, "=C5 * D5"]
- ];
-
- const range1 = sheet1.getRange("B2:E5");
- range1.values = data1;
- range1.format.autofitColumns();
-
- // Set up the second sample table.
- const sheet2 = context.workbook.worksheets.add("Sample2020Data");
- const data2 = [
- ["Product", "Qty", "Unit Price", "Total Price 2020", "Average Annual Price"],
- ["Almonds", 2, 8.0, "=C3 * D3", "=Sample2019Data!E3 + E3 / 2"],
- ["Coffee", 1, 36.5, "=C4 * D4", "=Sample2019Data!E4 + E4 / 2"],
- ["Chocolate", 5, 11.2, "=C5 * D5", "=Sample2019Data!E5 + E5 / 2"]
- ];
-
- const range2 = sheet2.getRange("B2:F5");
- range2.values = data2;
- range2.format.autofitColumns();
-
- // Style the tables.
- const header1 = range1.getRow(0);
- header1.format.fill.color = "#4472C4";
- header1.format.font.color = "white";
-
- const header2 = range2.getRow(0);
- header2.format.fill.color = "#4472C4";
- header2.format.font.color = "white";
-
- sheet2.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to find and highlight the precedents of the currently selected cell.
-
Precedents are cells referenced by the formula in a cell. A formula can also reference a cell that contains a formula, which results in a series of precedents. A "direct precedent" is a cell directly referenced by the selected formula. This sample shows how to return both the direct precedents and all of the precedents.
-
-
-
Set up
-
-
-
-
Try it out
-
-
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-areas.yaml b/samples/excel/42-range/range-areas.yaml
deleted file mode 100644
index cfbff6ec9..000000000
--- a/samples/excel/42-range/range-areas.yaml
+++ /dev/null
@@ -1,184 +0,0 @@
-order: 3
-id: excel-range-areas
-name: Discontiguous ranges (RangeAreas) and special cells
-description: 'Creates and uses RangeAreas, which are sets of ranges that need not be contiguous, through user selection and programmatic selection of special cells.'
-host: EXCEL
-api_set:
- ExcelApi: '1.9'
-script:
- content: |
- $("#reset").click(() => tryCatch(reset));
- $("#color-selected-ranges").click(() => tryCatch(colorSelectedRanges));
- $("#color-specified-ranges").click(() => tryCatch(colorSpecifiedRanges));
- $("#color-all-formula-ranges").click(() => tryCatch(colorAllFormulaRanges));
- $("#color-all-logical-text-ranges").click(() => tryCatch(colorAllLogicalAndTextRanges));
- $("#read-properties-specified-ranges").click(() => tryCatch(readPropertiesOfSpecifiedRanges));
-
- async function colorSelectedRanges() {
- await Excel.run(async (context) => {
-
- const selectedRanges = context.workbook.getSelectedRanges();
- selectedRanges.format.fill.color = "lightblue";
-
- await context.sync();
- })
- }
-
- async function colorSpecifiedRanges() {
- await Excel.run(async (context) => {
-
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const specifiedRanges = sheet.getRanges("D3:D5, G3:G5");
- specifiedRanges.format.fill.color = "pink";
-
- await context.sync();
- })
- }
-
- async function colorAllFormulaRanges() {
- await Excel.run(async (context) => {
-
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const usedRange = sheet.getUsedRange();
-
- // Find the ranges with formulas.
- const formulaRanges = usedRange.getSpecialCells("Formulas");
- formulaRanges.format.fill.color = "lightgreen";
-
- await context.sync();
- });
- }
-
- async function colorAllLogicalAndTextRanges() {
- await Excel.run(async (context) => {
-
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const usedRange = sheet.getUsedRange();
-
- // Find the ranges with either text or logical (boolean) values.
- const formulaRanges = usedRange.getSpecialCells("Constants", "LogicalText");
- formulaRanges.format.fill.color = "orange";
-
- return context.sync();
- });
- }
-
- async function readPropertiesOfSpecifiedRanges() {
- await Excel.run(async (context) => {
-
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const specifiedRanges = sheet.getRanges("C3:C5, E3:E5");
- specifiedRanges.load("format/fill/color, isEntireColumn, address, areaCount");
-
- await context.sync()
-
- // Non-boolean properties return null unless the
- // property value on all member ranges is the same.
- // (RangeAreas.address is an exception.)
- console.log("Color is: " + specifiedRanges.format.fill.color);
-
- // Boolean properties return false unless the
- // property is true on ALL member ranges.
- console.log("Each range is an entireColumn: " + specifiedRanges.isEntireColumn);
-
- // Returns a comma-delimited string of all the
- // addresses of the member ranges.
- console.log("Range addresses: " + specifiedRanges.address);
- console.log("Number of ranges: " + specifiedRanges.areaCount);
-
- await context.sync();
- });
- }
-
- async function reset() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const data = [
- ["Product", "Qty", "Category", "Unit Price", "Base Price", "Tax", "Total Charge", "Manager's Discount", "Final Price"],
- ["Almonds", 2, "Nuts", 7.50, "=C3 * E3", 0.1, "=SUM(F3,F3 * G3)", false, "=IF(I3 = TRUE, H3 * 0.9, H3)"],
- ["Coffee", 1, "Beverage", 34.50, "=C4 * E4", 0.0, "=SUM(F4,F4 * G4)", true, "=IF(I4 = TRUE, H4 * 0.9, H4)"],
- ["Chocolate", 5, "Candy", 9.56, "=C5 * E5", 0.2, "=SUM(F5,F5 * G5)", false, "=IF(I5 = TRUE, H5 * 0.9, H5)"]
- ];
-
- const range = sheet.getRange("B2:J5");
- range.values = data;
- range.format.autofitColumns();
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |
-
-
This sample shows how to apply actions simultaneously to multiple, discontiguous ranges. Some of these ranges are found using the Range object's getSpecialCells method.
-
-
-
-
Set up
-
-
Try it out
-
Select two or more ranges on the Sample worksheet. It doesn't matter if they have data or are contiguous. Then press Color selected ranges.
-
-
Press the next button to color ranges that are specified by hard-coded addresses in the JavaScript.
-
-
Add a formula to any cells you want on the Sample worksheet and press the next button.
-
-
Add text to any cells and add a logical (Boolean) value to any cells on the Sample worksheet and press the next button.
-
-
In Excel, select range C3:C5 and format its fill to a new color. Then set the fill for range E3:E5 to exactly the same color! Then press "Read properties of Qty and Unit Price ranges". Watch the console.
-
Next, change the fill color of one of the two ranges and press the button again.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-auto-fill.yaml b/samples/excel/42-range/range-auto-fill.yaml
deleted file mode 100644
index c6042f1d1..000000000
--- a/samples/excel/42-range/range-auto-fill.yaml
+++ /dev/null
@@ -1,156 +0,0 @@
-order: 1
-id: excel-range-auto-fill
-name: Auto fill
-description: Writes to cells with the auto fill feature.
-host: EXCEL
-api_set:
- ExcelApi: '1.10'
-script:
- content: |
- $("#setup-data").click(() => tryCatch(setupData));
- $("#setup-first-sums").click(() => tryCatch(setupFirstSums));
- $("#auto-fill-values").click(() => tryCatch(autoFillValues));
- $("#auto-fill-formats").click(() => tryCatch(autoFillFormats));
- $("#auto-fill-copy").click(() => tryCatch(autoFillCopy));
-
- async function autoFillValues() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const sumCell = sheet.getRange("F4");
-
- // Copy only the values and formulas, not the formatting. The formulas will be contextually updated based on their new locations.
- sumCell.autoFill("F4:F7", Excel.AutoFillType.fillValues);
- sumCell.format.autofitColumns();
- await context.sync();
- });
- }
-
- async function autoFillFormats() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const sumCell = sheet.getRange("K4");
-
- // Copy only the formatting, not the values and formulas.
- sumCell.autoFill("K4:K7", Excel.AutoFillType.fillFormats);
- sumCell.format.autofitColumns();
- await context.sync();
- });
- }
-
- async function autoFillCopy() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const sumCell = sheet.getRange("P4");
-
- // Copy everything. The formulas will be contextually updated based on their new locations.
- sumCell.autoFill("P4:P7", Excel.AutoFillType.fillCopy);
- sumCell.format.autofitColumns();
- await context.sync();
- });
- }
-
- async function setupData() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const data = [
- ["Fruit", "Q1", "Q2", "Q3", "Q4", 2017, "Q1", "Q2", "Q3", "Q4", 2018, "Q1", "Q2", "Q3", "Q4", 2019],
- ["Quinces", 500, 2000, 5000, 1500, , 600, 2200, 5400, 1300, , 300, 1500, 4300, 1200, ""],
- ["Plums", 700, 900, 1300, 800, , 800, 1000, 2000, 700, , 300, 600, 1100, 700, ""],
- ["Apples", 8000, 3000, 4500, 7500, , 8900, 4000, 3500, 4500, , 6000, 2500, 4500, 9500, ""],
- ["Peaches", 12000, 7000, 8000, 13000, , 16000, 10000, 8500, 12000, , 11000, 5600, 6500, 11000, ""]
- ];
-
- sheet.getRange("A3:P7").values = data;
- sheet.getRange("A1").values = [["Fruit Sales"]];
- sheet.getRange("A1").style = "Heading1";
- sheet.getRanges("B2:P3,A3:A7").format.font.bold = true;
-
- sheet.getRange("A1:P7").format.autofitColumns();
- sheet.activate();
-
- await context.sync();
- });
- }
-
- async function setupFirstSums() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const sumRange = sheet.getRange("F4");
- sumRange.formulas = [["=SUM(B4:E4)"]];
- sumRange.format.fill.color = "LightBlue";
- sumRange.format.font.bold = true;
- sheet.getRanges("K4,P4").copyFrom("F4", Excel.RangeCopyType.all);
- sheet.getRanges("F4,K4,P4").format.autofitColumns();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback, option?) {
- try {
- await callback(option);
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to provide cell data for surrounding cells using auto fill.
-
-
-
-
Set up
-
-
-
-
-
-
-
Try it out
-
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-copyfrom.yaml b/samples/excel/42-range/range-copyfrom.yaml
deleted file mode 100644
index 0db6cc1ac..000000000
--- a/samples/excel/42-range/range-copyfrom.yaml
+++ /dev/null
@@ -1,225 +0,0 @@
-order: 2
-id: excel-range-copyfrom
-name: Copy and paste ranges
-description: Copies or moves data and formatting from one range to another.
-host: EXCEL
-api_set:
- ExcelApi: '1.10'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#copyAll").click(() => tryCatch(copyAll));
- $("#copyFormula").click(() => tryCatch(copyFormula));
- $("#copyFormulaResult").click(() => tryCatch(copyFormulaResult));
- $("#copySingleAcrossRange").click(() => tryCatch(copySingleAcrossRange));
- $("#copyOnlyFormat").click(() => tryCatch(copyOnlyFormat));
- $("#skipBlanks").click(() => tryCatch(skipBlanks));
- $("#transpose").click(() => tryCatch(transpose));
- $("#move").click(() => tryCatch(move));
-
- async function copyAll() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the copied data.
- sheet.getRange("F1").values = [["Copied Range"]];
-
- // Copy a range starting at a single cell destination.
- sheet.getRange("G1").copyFrom("A1:E1");
- await context.sync();
- });
- }
-
- async function copyFormula() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the copied data.
- sheet.getRange("F2").values = [["Copied Formula"]];
-
- // Copy a range preserving the formulas.
- // Note: non-formula values are copied over as is.
- sheet.getRange("G2").copyFrom("A1:E1", Excel.RangeCopyType.formulas);
- await context.sync();
- });
- }
-
- async function copyFormulaResult() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the copied data.
- sheet.getRange("F3").values = [["Copied Formula Result"]];
-
- // Copy the resulting value of a formula.
- sheet.getRange("G3").copyFrom("E1", Excel.RangeCopyType.values);
- await context.sync();
- });
- }
-
- async function copySingleAcrossRange() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the copied data.
- sheet.getRange("F4").values = [["Single Source"]];
-
- // Copy a single cell across an entire range.
- sheet.getRange("G4:K4").copyFrom("A1", Excel.RangeCopyType.values);
- await context.sync();
- });
- }
-
- async function copyOnlyFormat() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the copied data.
- sheet.getRange("F5").values = [["Copied Formatting"]];
-
- // Copy only the formatting of the cells.
- sheet.getRange("G5").copyFrom("A1:E1", Excel.RangeCopyType.formats);
- await context.sync();
- });
- }
-
- async function skipBlanks() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the copied data.
- sheet.getRange("F6").values = [["Copied Without Blanks"]];
-
- // Fill the destination range so we can see the blank being skipped.
- sheet.getRange("G6:K6").values = [["Old Data", "Old Data", "Old Data", "Old Data", "Old Data"]]
-
- // Copy a range, omitting the blank cells so existing data is not overwritten in those cells.
- sheet.getRange("G6").copyFrom("A1:E1",
- Excel.RangeCopyType.all,
- true, // skipBlanks
- false); // transpose
- await context.sync();
- });
- }
-
- async function transpose() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the transposed data.
- sheet.getRange("F7").values = [["Transpose"]];
-
- // Transpose a horizontal range of data into a vertical range.
- sheet.getRange("G7").copyFrom("A1:E1",
- Excel.RangeCopyType.all,
- false, // skipBlanks
- true); // transpose
- await context.sync();
- });
- }
-
- async function move() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- // Place a label in front of the moved data.
- sheet.getRange("F12").values = [["Moved Range:"]];
-
- // Move the range from A1:E1 to G12:K12.
- sheet.getRange("A1:E1").moveTo("G12");
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
-
- const sheet = context.workbook.worksheets.add("Sample");
- sheet.getRange("A1:D1").values = [["3", "5", "7", ""]];
- sheet.getRange("A1:D1").format.font.italic = true;
- sheet.getRange("A1:D1").format.font.color = "DarkMagenta";
- sheet.getRange("E1").formulas = [["=SUM(A1:D1)"]];
- sheet.getRange("E1").format.font.bold = true;
- sheet.getRange("E1").format.fill.color = "LightGreen";
- sheet.getRange("F1").format.columnWidth = 120;
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to copy data and formatting from one range (A1:E1) to another.
-
-
-
Setup
-
-
-
-
Try it out
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |-
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-dependents.yaml b/samples/excel/42-range/range-dependents.yaml
deleted file mode 100644
index b79542f62..000000000
--- a/samples/excel/42-range/range-dependents.yaml
+++ /dev/null
@@ -1,174 +0,0 @@
-order: 22
-id: excel-range-dependents
-name: Dependents
-description: This sample shows how to find and highlight the dependents of the currently selected cell. Dependent cells contain formulas that refer to other cells.
-host: EXCEL
-api_set:
- ExcelAPI: '1.15'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#select-D3").click(() => tryCatch(selectD3));
- $("#get-all-dependents").click(() => tryCatch(getAllDependents));
- $("#clear-highlighting").click(() => tryCatch(clearFormatting));
-
- async function selectD3() {
- // This function selects a cell with dependents across both worksheets.
- await Excel.run(async (context) => {
- // Activate the sample worksheet.
- const sheet = context.workbook.worksheets.getItem("Sample2019Data");
- sheet.activate();
-
- // Select cell D3.
- const range = sheet.getRange("D3");
- range.select();
- await context.sync();
- });
- }
-
- async function getAllDependents() {
- // This function highlights all the dependent cells of the active cell.
- // Dependent cells contain formulas that refer to other cells.
- await Excel.run(async (context) => {
- // Get addresses of the active cell's dependent cells.
- const range = context.workbook.getActiveCell();
- const dependents = range.getDependents();
- range.load("address");
- dependents.areas.load("address");
- await context.sync();
-
- console.log(`All dependent cells of ${range.address}:`);
-
- // Use the dependents API to loop through dependents of the active cell.
- for (let i = 0; i < dependents.areas.items.length; i++) {
- // Highlight and print out the address of each dependent cell.
- dependents.areas.items[i].format.fill.color = "Orange";
- console.log(` ${dependents.areas.items[i].address}`);
- }
- await context.sync();
- });
- }
-
- async function clearFormatting() {
- // This function removes highlighting from dependent cells.
- await Excel.run(async (context) => {
- const sheet1 = context.workbook.worksheets.getItem("Sample2019Data");
- const range1 = sheet1.getRange("B3:E5");
- range1.format.fill.clear();
-
- const sheet2 = context.workbook.worksheets.getItem("Sample2020Data");
- const range2 = sheet2.getRange("B3:F5");
- range2.format.fill.clear();
-
- await context.sync();
- });
- }
-
- /** Create two sample tables on different worksheets, with functions that span the tables. */
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample2019Data").delete();
- context.workbook.worksheets.getItemOrNullObject("Sample2020Data").delete();
-
- // Set up the first sample table.
- const sheet1 = context.workbook.worksheets.add("Sample2019Data");
- const data1 = [
- ["Product", "Qty", "Unit Price", "Total Price 2019"],
- ["Almonds", 2, 7.5, "=C3 * D3"],
- ["Coffee", 1, 34.5, "=C4 * D4"],
- ["Chocolate", 5, 9.56, "=C5 * D5"]
- ];
-
- const range1 = sheet1.getRange("B2:E5");
- range1.values = data1;
- range1.format.autofitColumns();
-
- // Set up the second sample table.
- const sheet2 = context.workbook.worksheets.add("Sample2020Data");
- const data2 = [
- ["Product", "Qty", "Unit Price", "Total Price 2020", "Average Annual Price"],
- ["Almonds", 2, 8.0, "=C3 * D3", "=Sample2019Data!E3 + E3 / 2"],
- ["Coffee", 1, 36.5, "=C4 * D4", "=Sample2019Data!E4 + E4 / 2"],
- ["Chocolate", 5, 11.2, "=C5 * D5", "=Sample2019Data!E5 + E5 / 2"]
- ];
-
- const range2 = sheet2.getRange("B2:F5");
- range2.values = data2;
- range2.format.autofitColumns();
-
- // Style the tables.
- const header1 = range1.getRow(0);
- header1.format.fill.color = "#4472C4";
- header1.format.font.color = "white";
-
- const header2 = range2.getRow(0);
- header2.format.fill.color = "#4472C4";
- header2.format.font.color = "white";
-
- sheet2.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to find and highlight the dependents of the currently selected cell.
-
Dependent cells contain formulas that refer to other cells.
-
-
-
Set up
-
-
-
-
Try it out
-
Cell D3 has dependents across worksheets.
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-direct-dependents.yaml b/samples/excel/42-range/range-direct-dependents.yaml
deleted file mode 100644
index 27f0ce290..000000000
--- a/samples/excel/42-range/range-direct-dependents.yaml
+++ /dev/null
@@ -1,169 +0,0 @@
-order: 21
-id: excel-direct-dependents
-name: Direct dependents
-description: This sample shows how to find and highlight the direct dependents of the currently selected cell. Dependent cells contain formulas that refer to other cells.
-host: EXCEL
-api_set:
- ExcelAPI: '1.13'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#select-D3").click(() => tryCatch(selectD3));
- $("#select-E4").click(() => tryCatch(selectE4));
- $("#get-direct-dependents").click(() => tryCatch(getDirectDependents));
-
- /** Select a cell with direct dependents on the same worksheet. */
- async function selectD3() {
- await Excel.run(async (context) => {
- // Activate the sample worksheet.
- const sheet = context.workbook.worksheets.getItem("Sample2019Data");
- sheet.activate();
-
- // Select cell D3.
- const range = sheet.getRange("D3");
- range.select();
- await context.sync();
- });
- }
-
- /** Select a cell with direct dependents across worksheets. */
- async function selectE4() {
- await Excel.run(async (context) => {
- // Activate the sample worksheet.
- const sheet = context.workbook.worksheets.getItem("Sample2019Data");
- sheet.activate();
-
- // Select cell E4.
- const range = sheet.getRange("E4");
- range.select();
- await context.sync();
- });
- }
-
- async function getDirectDependents() {
- await Excel.run(async (context) => {
- // Direct dependents are cells that contain formulas that refer to other cells.
- let range = context.workbook.getActiveCell();
- let directDependents = range.getDirectDependents();
- range.load("address");
- directDependents.areas.load("address");
- await context.sync();
-
- console.log(`Direct dependent cells of ${range.address}:`);
-
- // Use the direct dependents API to loop through direct dependents of the active cell.
- for (let i = 0; i < directDependents.areas.items.length; i++) {
- // Highlight and print the address of each dependent cell.
- directDependents.areas.items[i].format.fill.color = "Yellow";
- console.log(` ${directDependents.areas.items[i].address}`);
- }
- await context.sync();
- });
- }
-
- /** Create two sample tables on different worksheets with methods that span the tables. */
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample2019Data").delete();
- context.workbook.worksheets.getItemOrNullObject("Sample2020Data").delete();
-
- // Set up the first sample table.
- const sheet1 = context.workbook.worksheets.add("Sample2019Data");
- const data1 = [
- ["Product", "Qty", "Unit Price", "Total Price 2019"],
- ["Almonds", 2, 7.5, "=C3 * D3"],
- ["Coffee", 1, 34.5, "=C4 * D4"],
- ["Chocolate", 5, 9.56, "=C5 * D5"]
- ];
-
- const range1 = sheet1.getRange("B2:E5");
- range1.values = data1;
- range1.format.autofitColumns();
-
- // Set up the second sample table.
- const sheet2 = context.workbook.worksheets.add("Sample2020Data");
- const data2 = [
- ["Product", "Qty", "Unit Price", "Total Price 2020", "Average Annual Price"],
- ["Almonds", 2, 8.0, "=C3 * D3", "=Sample2019Data!E3 + E3 / 2"],
- ["Coffee", 1, 36.5, "=C4 * D4", "=Sample2019Data!E4 + E4 / 2"],
- ["Chocolate", 5, 11.2, "=C5 * D5", "=Sample2019Data!E5 + E5 / 2"]
- ];
- const range2 = sheet2.getRange("B2:F5");
- range2.values = data2;
- range2.format.autofitColumns();
-
- // Style the tables.
- const header1 = range1.getRow(0);
- header1.format.fill.color = "#4472C4";
- header1.format.font.color = "white";
- const header2 = range2.getRow(0);
- header2.format.fill.color = "#4472C4";
- header2.format.font.color = "white";
- sheet2.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to find and highlight the dependents of the currently selected cell. Dependent cells contain formulas that refer to other cells.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
Cells in the 'E' column have direct dependents on the same worksheet. Cells in the 'F' column have direct dependents on another worksheet.
-
-
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-find.yaml b/samples/excel/42-range/range-find.yaml
deleted file mode 100644
index 5037390c8..000000000
--- a/samples/excel/42-range/range-find.yaml
+++ /dev/null
@@ -1,171 +0,0 @@
-order: 4
-id: excel-range-find
-name: Find text matches within a range
-description: Finds a cell within a range based on string matching.
-host: EXCEL
-api_set:
- ExcelApi: '1.9'
-script:
- content: |-
- $("#setup").click(() => tryCatch(setup));
- $("#findText").click(() => tryCatch(findText));
- $("#findTextWithNullCheck").click(() => tryCatch(findTextWithNullCheck));
- $("#toggleComplete").click(() => tryCatch(toggleComplete));
- $("#toggleCase").click(() => tryCatch(toggleCase));
- $("#toggleDirection").click(() => tryCatch(toggleDirection));
-
- let isCompleteMatchToggle = false;
- let isMatchCaseToggle = false;
- let searchDirectionToggle = Excel.SearchDirection.forward;
-
- async function findText() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const table = sheet.tables.getItem("ExpensesTable");
- const searchRange = table.getRange();
-
- // NOTE: If no match is found, an ItemNotFound error
- // is thrown when Range.find is evaluated.
- const foundRange = searchRange.find($("#searchText").val().toString(), {
- completeMatch: isCompleteMatchToggle,
- matchCase: isMatchCaseToggle,
- searchDirection: searchDirectionToggle
- });
-
- foundRange.load("address");
- await context.sync();
-
-
- console.log(foundRange.address);
- });
- }
-
- async function findTextWithNullCheck() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const table = sheet.tables.getItem("ExpensesTable");
- const searchRange = table.getRange();
- const foundRange = searchRange.findOrNullObject($("#searchText").val().toString(), {
- completeMatch: isCompleteMatchToggle,
- matchCase: isMatchCaseToggle,
- searchDirection: searchDirectionToggle
- });
-
- foundRange.load("address");
- await context.sync();
-
- if (foundRange.isNullObject) {
- console.log("Text not found");
- } else {
- console.log(foundRange.address);
- }
- });
- }
-
- function toggleComplete() {
- isCompleteMatchToggle = !isCompleteMatchToggle;
- console.log("Finding complete match = " + isCompleteMatchToggle);
- }
-
- function toggleCase() {
- isMatchCaseToggle = !isMatchCaseToggle;
- console.log("Finding matched case = " + isMatchCaseToggle);
- }
-
- function toggleDirection() {
- searchDirectionToggle = searchDirectionToggle === Excel.SearchDirection.forward ? Excel.SearchDirection.backwards : Excel.SearchDirection.forward;
- console.log("Search direction = " + searchDirectionToggle);
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const expensesTable = sheet.tables.add("A1:D1", true /*hasHeaders*/);
- expensesTable.name = "ExpensesTable";
- expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]];
- expensesTable.rows.add(null /*add at the end*/, [
- ["1/1/2017", "The Phone Company", "Communications", "$120"],
- ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"],
- ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"],
- ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"],
- ["1/11/2017", "The Phone Company", "communications", "$5"],
- ["1/15/2017", "Coho Vineyard (Wine)", "Groceries", "$60"],
- ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to find a cell with a matching string value within a range.
-
-
-
Setup
-
-
-
-
Try it out
-
Enter text to search for in the box below and press Find text or Find text with null check to display the found text's address in the console.
-
-
-
-
Toggle the following search options to test different search behaviors.
-
-
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |-
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-get-range-edge.yaml b/samples/excel/42-range/range-get-range-edge.yaml
deleted file mode 100644
index a16b965c3..000000000
--- a/samples/excel/42-range/range-get-range-edge.yaml
+++ /dev/null
@@ -1,232 +0,0 @@
-order: 20
-id: excel-range-get-range-edge
-name: Select used range edge
-description: 'This sample shows how to select the edges of the used range, based on the currently selected range.'
-host: EXCEL
-api_set:
- ExcelAPI: '1.13'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#select-E9").click(() => tryCatch(selectE9));
- $("#select-D8-E9").click(() => tryCatch(selectD8E9));
- $("#get-range-edge-left").click(() => tryCatch(getRangeEdgeLeft));
- $("#get-range-edge-up").click(() => tryCatch(getRangeEdgeUp));
- $("#get-extended-range-right").click(() => tryCatch(getExtendedRangeRight));
- $("#get-extended-range-down").click(() => tryCatch(getExtendedRangeDown));
-
- async function getRangeEdgeLeft() {
- await Excel.run(async (context) => {
- // Get the selected range.
- const range = context.workbook.getSelectedRange();
-
- // Get the active cell in the workbook.
- const activeCell = context.workbook.getActiveCell();
-
- // Get the left-most cell of the current used range.
- // This method acts like the Ctrl+Arrow key keyboard shortcut while a range is selected.
- const rangeEdge = range.getRangeEdge(
- "Left", // Specify the direction as a string.
- activeCell // If the selected range contains more than one cell, the active cell must be defined.
- );
-
- // Select the edge of the range.
- rangeEdge.select();
-
- await context.sync();
- });
- }
-
- async function getRangeEdgeUp() {
- await Excel.run(async (context) => {
- // Get the selected range.
- const range = context.workbook.getSelectedRange();
-
- // Specify the direction with the `KeyboardDirection` enum.
- const direction = Excel.KeyboardDirection.up;
-
- // Get the active cell in the workbook.
- const activeCell = context.workbook.getActiveCell();
-
- // Get the top-most cell of the current used range.
- // This method acts like the Ctrl+Arrow key keyboard shortcut while a range is selected.
- const rangeEdge = range.getRangeEdge(
- direction,
- activeCell // If the selected range contains more than one cell, the active cell must be defined.
- );
- rangeEdge.select();
-
- await context.sync();
- });
- }
-
- async function getExtendedRangeRight() {
- await Excel.run(async (context) => {
- // Get the selected range.
- const range = context.workbook.getSelectedRange();
-
- // Get the active cell in the workbook.
- const activeCell = context.workbook.getActiveCell();
-
- // Get all the cells from the currently selected range to the right-most edge of the used range.
- // This method acts like the Ctrl+Shift+Arrow key keyboard shortcut while a range is selected.
- const extendedRange = range.getExtendedRange(
- "Right", // Specify the direction as a string.
- activeCell // If the selected range contains more than one cell, the active cell must be defined.
- );
- extendedRange.select();
-
- await context.sync();
- });
- }
-
- async function getExtendedRangeDown() {
- await Excel.run(async (context) => {
- // Get the selected range.
- const range = context.workbook.getSelectedRange();
-
- // Specify the direction with the `KeyboardDirection` enum.
- const direction = Excel.KeyboardDirection.down;
-
- // Get the active cell in the workbook.
- const activeCell = context.workbook.getActiveCell();
-
- // Get all the cells from the currently selected range to the bottom-most edge of the used range.
- // This method acts like the Ctrl+Shift+Arrow key keyboard shortcut while a range is selected.
- const extendedRange = range.getExtendedRange(
- direction,
- activeCell // If the selected range contains more than one cell, the active cell must be defined.
- );
- extendedRange.select();
-
- await context.sync();
- });
- }
-
- /** Select a range with one cell. */
- async function selectE9() {
- await Excel.run(async (context) => {
- // Get the active worksheet.
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Select cell E9.
- const range = sheet.getRange("E9");
- range.select();
- await context.sync();
- });
- }
-
- /** Select a range with multiple cells. */
- async function selectD8E9() {
- await Excel.run(async (context) => {
- // Get the active worksheet.
- const sheet = context.workbook.worksheets.getActiveWorksheet();
-
- // Select range D8:E9.
- const range = sheet.getRange("D8:E9");
- range.select();
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const expensesTable = sheet.tables.add("C5:F5", true /*hasHeaders*/);
- expensesTable.name = "ExpensesTable";
-
- expensesTable.getHeaderRowRange().values = [["Date", "Merchant", "Category", "Amount"]];
-
- expensesTable.rows.add(null /*add at the end*/, [
- ["1/1/2017", "The Phone Company", "Communications", "$120"],
- ["1/2/2017", "Northwind Electric Cars", "Transportation", "$142"],
- ["1/5/2017", "Best For You Organics Company", "Groceries", "$27"],
- ["1/10/2017", "Coho Vineyard", "Restaurant", "$33"],
- ["1/11/2017", "Bellows College", "Education", "$350"],
- ["1/15/2017", "Trey Research", "Other", "$135"],
- ["1/15/2017", "Best For You Organics Company", "Groceries", "$97"]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |-
-
-
This sample shows how to select the edges of the used range, based on the currently selected range.
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
The first type of range edge selection selects the cell at the furthest edge of the current used range, in the directions up or left. This action matches the result of using the Ctrl+Arrow key keyboard shortcut while a range is selected.
-
-
-
-
The second type of range edge selection selects all the cells from the currently selected range to the furthest edge of the used range, in the directions right or down. This action matches the result of using the Ctrl+Shift+Arrow key keyboard shortcut while a range is selected.
This sample shows how to remove rows with duplicate column values from a range.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
Note that blank cells are considered in the remove duplicate checks. Since the duplicates are removed from the entire original range, the numbers logged to the console may be higher than expected.
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/range-text-orientation.yaml b/samples/excel/42-range/range-text-orientation.yaml
deleted file mode 100644
index 7211ee30b..000000000
--- a/samples/excel/42-range/range-text-orientation.yaml
+++ /dev/null
@@ -1,127 +0,0 @@
-order: 15
-id: excel-range-text-orientation
-name: Text orientation
-description: Gets and sets the text orientation within a range.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#set-text-orientation").click(() => tryCatch(setTextOrientation));
- $("#get-text-orientation").click(() => tryCatch(getTextOrientation));
-
- async function setTextOrientation() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const range = sheet.getRange("B2:E2");
-
- // Set textOrientation to either an integer between -90 and 90
- // or to 180 for vertically-oriented text.
- range.format.textOrientation = 90;
-
- await context.sync();
- });
- }
-
- async function getTextOrientation() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const range = sheet.getRange("B2:E2");
- range.load("address, format/textOrientation");
-
- await context.sync();
-
- let textOrientation = range.format.textOrientation === null ?
- "null (which indicates that the text orientation for cells within the specified range is not uniform)" :
- range.format.textOrientation;
-
- console.log(`The text orientation within the range "${range.address}" is ${textOrientation}.`);
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- const data = [
- ["Product", "Qty", "Unit Price", "Total Price"],
- ["Almonds", 2, 7.50, "=C3 * D3"],
- ["Coffee", 1, 34.50, "=C4 * D4"],
- ["Chocolate", 5, 9.56, "=C5 * D5"]
- ];
-
- const range = sheet.getRange("B2:E5");
- range.values = data;
- range.format.autofitColumns();
-
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |
-
-
This sample shows how to set and get the text orientation within a range.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/selected-range.yaml b/samples/excel/42-range/selected-range.yaml
deleted file mode 100644
index 4c14a5798..000000000
--- a/samples/excel/42-range/selected-range.yaml
+++ /dev/null
@@ -1,87 +0,0 @@
-order: 12
-id: excel-range-selected-range
-name: Selected range
-description: Gets and sets the currently selected range.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.1'
-script:
- content: |
- $("#get-selection").click(() => tryCatch(getSelection));
- $("#set-selection").click(() => tryCatch(setSelection));
-
- async function getSelection() {
- await Excel.run(async (context) => {
- const range = context.workbook.getSelectedRange();
- range.load("address");
-
- await context.sync();
-
- console.log(`The address of the selected range is "${range.address}"`)
- });
- }
-
- async function setSelection() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getActiveWorksheet();
- const range = sheet.getRange("B2:E6");
-
- range.select();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |
-
-
This sample shows how to get and set the currently selected range.
This sample shows how to set and get values and formulas for a range.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
-
-
-
-
-
-
-
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/style.yaml b/samples/excel/42-range/style.yaml
deleted file mode 100644
index 2ad8bcd6c..000000000
--- a/samples/excel/42-range/style.yaml
+++ /dev/null
@@ -1,235 +0,0 @@
-order: 14
-id: excel-range-style
-name: Style
-description: 'Creates a custom style, applies a custom and built-in styles to a range, gets style properties, and deletes the custom style.'
-author: siewmoi
-host: EXCEL
-api_set:
- ExcelApi: '1.7'
-script:
- content: |+
- $("#setup").click(() => tryCatch(setup));
- $("#add-new-style").click(() => tryCatch(addNewStyle));
- $("#apply-new-style").click(() => tryCatch(applyNewStyle));
- $("#apply-built-in-style").click(() => tryCatch(applyBuiltInStyle));
- $("#get-style-font").click(() => tryCatch(getStyleFontProperties));
- $("#get-style-alignment").click(() => tryCatch(getStyleAlignmentProperties));
- $("#delete-new-style").click(() => tryCatch(deleteNewStyle));
-
- async function addNewStyle() {
- await Excel.run(async (context) => {
- let styles = context.workbook.styles;
-
- // Add a new style to the style collection.
- // Styles is in the Home tab ribbon.
- styles.add("Diagonal Orientation Style");
-
- let newStyle = styles.getItem("Diagonal Orientation Style");
-
- // The "Diagonal Orientation Style" properties.
- newStyle.textOrientation = 38;
- newStyle.autoIndent = true;
- newStyle.includeProtection = true;
- newStyle.shrinkToFit = true;
- newStyle.locked = false;
-
- await context.sync();
-
- console.log("Successfully added a new style with diagonal orientation to the Home tab ribbon.");
- });
- }
-
- async function applyNewStyle() {
- await Excel.run(async (context) => {
- let worksheet = context.workbook.worksheets.getItem("Sample");
- let range = worksheet.getRange("A1:E1");
- // Apply new style.
- range.style = ("Diagonal Orientation Style");
- range.format.verticalAlignment = "Justify";
-
- await context.sync();
- });
- }
-
- async function applyBuiltInStyle() {
- await Excel.run(async (context) => {
- let worksheet = context.workbook.worksheets.getItem("Sample");
- let range = worksheet.getRange("A1:E1");
-
- // Apply built-in style.
- // Styles are in the Home tab ribbon.
- range.style = Excel.BuiltInStyle.neutral;
- range.format.horizontalAlignment = "Right";
-
- await context.sync();
- });
- }
-
- async function getStyleFontProperties() {
- await Excel.run(async (context) => {
- let style = context.workbook.styles.getItem("Normal");
- style.font.load("bold, color, italic, name, size");
- style.fill.load("color");
-
- await context.sync();
-
- console.log("Bold: " + style.font.bold);
- console.log("Font color: " + style.font.color);
- console.log("Italic: " + style.font.italic);
- console.log("Name: " + style.font.name);
- console.log("Size: " + style.font.size);
- console.log("Fill color: " + style.fill.color);
- });
- }
-
- async function getStyleAlignmentProperties() {
- await Excel.run(async (context) => {
- let style = context.workbook.styles.getItem("Diagonal Orientation Style");
- style.load("textOrientation, horizontalAlignment, autoIndent, readingOrder, wrapText, includeProtection, shrinkToFit, locked");
-
- await context.sync();
-
- console.log("Orientation: " + style.textOrientation);
- console.log("Horizontal alignment: " + style.horizontalAlignment);
- console.log("Add indent: " + style.autoIndent);
- console.log("Reading order: " + style.readingOrder);
- console.log("Wrap text: " + style.wrapText);
- console.log("Include protection: " + style.includeProtection);
- console.log("Shrink to fit: " + style.shrinkToFit);
- console.log("Style locked: " + style.locked);
- });
- }
-
- async function deleteNewStyle() {
- await Excel.run(async (context) => {
- let style = context.workbook.styles.getItem("Diagonal Orientation Style");
-
- // Delete the diagonal orientation style from the style collection.
- // Styles are in the Home tab ribbon.
- style.delete();
-
- await context.sync();
-
- console.log("Successfully deleted the diagonal orientation style from the Home tab ribbon.");
- });
- }
-
- async function setup() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let salesTable = sheet.tables.add('A1:E1', true);
- salesTable.name = "SalesTable";
-
- salesTable.getHeaderRowRange().values = [["Bicycle Parts Product", "Quarter 1", "Quarter 2", "Quarter 3", "Quarter 4"]];
-
- salesTable.rows.add(null, [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]
- ]);
-
- sheet.getUsedRange().format.autofitColumns();
- sheet.getUsedRange().format.autofitRows();
-
- sheet.activate();
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- }
- catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
-
-
- language: typescript
-template:
- content: |
-
-
This sample shows how to add, apply, get and delete styles.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
Add new style will throw an error if the style has already been added.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Clean up
-
Delete new style throws an error if the style doesn't exist (that is, hasn't been added). Deleting the style also causes the other buttons using the style to fail.
-
-
- language: html
-style:
- content: |-
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/42-range/used-range.yaml b/samples/excel/42-range/used-range.yaml
deleted file mode 100644
index ceb41f352..000000000
--- a/samples/excel/42-range/used-range.yaml
+++ /dev/null
@@ -1,149 +0,0 @@
-order: 17
-id: excel-range-used-range
-name: Used range
-description: Tests for a used range and creates a chart from a table only if there's data in the table.
-author: OfficeDev
-host: EXCEL
-api_set:
- ExcelApi: '1.4'
-script:
- content: |
- $("#setup").click(() => tryCatch(setup));
- $("#try-create-chart-from-table").click(() => tryCatch(tryCreateChartFromEmptyTable));
- $("#fill-table").click(() => tryCatch(fillTable));
-
- async function tryCreateChartFromEmptyTable() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const salesTable = sheet.tables.getItem("SalesTable");
- const dataRange = salesTable.getDataBodyRange();
-
- // Pass true so only cells with values count as used
- const usedDataRange = dataRange.getUsedRangeOrNullObject(
- true /* valuesOnly */
- );
-
- //Must sync before reading value returned from *OrNullObject method/property.
- await context.sync();
-
- if (usedDataRange.isNullObject) {
- console.log("Need Data to Make Chart");
- console.log("To create a meaningful chart, press 'Fill the table' (or add names to the Product column and numbers to some of the other cells). Then press 'Try to create chart' again.");
- } else {
- const chart = sheet.charts.add(
- Excel.ChartType.columnClustered,
- dataRange,
- "Columns"
- );
- chart.setPosition("A15", "F30");
- chart.title.text = "Quarterly sales chart";
- chart.legend.position = "Right";
- chart.legend.format.fill.setSolidColor("white");
- chart.dataLabels.format.font.size = 15;
- chart.dataLabels.format.font.color = "black";
- }
-
- await context.sync();
- });
- }
-
- async function fillTable() {
- await Excel.run(async (context) => {
- const sheet = context.workbook.worksheets.getItem("Sample");
- const salesTable = sheet.tables.getItem("SalesTable");
- const dataRange = salesTable.getDataBodyRange();
- dataRange.values = [
- ["Frames", 5000, 7000, 6544, 4377],
- ["Saddles", 400, 323, 276, 651],
- ["Brake levers", 12000, 8766, 8456, 9812],
- ["Chains", 1550, 1088, 692, 853],
- ["Mirrors", 225, 600, 923, 544],
- ["Spokes", 6005, 7634, 4589, 8765]];
-
- dataRange.format.autofitColumns();
- await context.sync();
- });
- }
-
- async function setup() {
- await Excel.run(async context => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
-
- let salesTable = sheet.tables.add("B2:F2", true /* hasHeaders */);
- salesTable.name = "SalesTable";
- salesTable.showTotals = true;
- salesTable.getHeaderRowRange().values = [["Product", "Qtr1", "Qtr2", "Qtr3", "Qtr4"]];
-
- // The table should be created wtih no data.
- salesTable.rows.add(null, [
- [null, null, null, null, null],
- [null, null, null, null, null],
- [null, null, null, null, null],
- [null, null, null, null, null],
- [null, null, null, null, null],
- [null, null, null, null, null]]);
- sheet.activate();
-
- await context.sync();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- language: typescript
-template:
- content: |
-
-
This sample creates a chart from a table, but only if there's data in the table.
This sample shows how to change the visbility of a worksheet.
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
-
-
- language: html
-style:
- content: |
- section.samples {
- margin-top: 20px;
- }
-
- section.samples .ms-Button, section.setup .ms-Button {
- display: block;
- margin-bottom: 5px;
- margin-left: 20px;
- min-width: 80px;
- }
- language: css
-libraries: |
- https://appsforoffice.microsoft.com/lib/1/hosted/office.js
- @types/office-js
-
- office-ui-fabric-js@1.4.0/dist/css/fabric.min.css
- office-ui-fabric-js@1.4.0/dist/css/fabric.components.min.css
-
- core-js@2.4.1/client/core.min.js
- @types/core-js
-
- jquery@3.1.1
- @types/jquery@3.3.1
\ No newline at end of file
diff --git a/samples/excel/90-scenarios/currency-converter.yaml b/samples/excel/90-scenarios/currency-converter.yaml
deleted file mode 100644
index 7e57e9818..000000000
--- a/samples/excel/90-scenarios/currency-converter.yaml
+++ /dev/null
@@ -1,194 +0,0 @@
-order: 5
-id: excel-scenarios-currency-converter
-name: Currency Converter
-description: Uses an exchange rate API to convert currency values based on their original transaction times.
-author: cakriwut
-host: EXCEL
-api_set:
- ExcelApi: '1.4'
-script:
- content: |
- /*
- * Copyright (c) Riwut Libinuko. All rights reserved. Licensed under the MIT license.
- */
-
- declare let moment: any;
- const tableName = "TransactionTable";
-
- let tableSetup: Record = {};
-
- $("#convert").click(() => tryCatch(convert));
- $("#setup").click(() => tryCatch(setupSample));
-
- /** Main converting function **/
- async function convert() {
- await Excel.run(async (context) => {
- const table = context.workbook.tables.getItem(tableName);
- table.columns.load("items");
- table.rows.load("items,value");
- await context.sync();
-
- if (!isTableValid(table.columns.items)) {
- console.error(
- 'Error: Some of default table header is missing. Required headers: \r\n"Currency","Price (Currency)","Transaction Date","Base","Price in Base"'
- );
- return;
- }
-
- const convertedCurrency = await Promise.all(
- table.rows.items.map( (row,idx) => {
- const priceInBase = row.values[0][tableSetup["Price in Base"]];
- const priceInCurrency = row.values[0][tableSetup["Price (Currency)"]];
- const transactionDate = row.values[0][tableSetup["Transaction Date"]];
- const currency = row.values[0][tableSetup["Currency"]];
- const baseCurrency = row.values[0][tableSetup["Base"]];
-
- if (priceInBase === "") {
- const dateMoment = moment.fromOADate(transactionDate);
- const period = dateMoment.format("YYYY-MM-DD");
- const queryUrl = convertValue(currency, baseCurrency, period, period);
-
- const result = fetch(queryUrl).then(response => response.json());
- return result;
- } else {
- return -1;
- }
- })
- );
-
- let index =0;
- let skippedRows = [];
- for (let row of table.rows.items) {
- const priceBaseRange = row.getRange().getCell(0, tableSetup["Price in Base"]);
- const priceInCurrency = row.values[0][tableSetup["Price (Currency)"]];
- const baseCurrency = row.values[0][tableSetup["Base"]];
-
- if (convertedCurrency[index] == -1) {
- skippedRows.push(index+1);
- } else {
- const converted = convertedCurrency[index].rates[baseCurrency] * priceInCurrency;
- priceBaseRange.values = [[converted]];
- }
- index++;
- }
-
- if(skippedRows.length > 0) {
- if(skippedRows.length == 1) {
- console.info(`Row: ${skippedRows.join(',')} has been converted. Skipped.`);
- } else {
- console.info(`Rows: ${skippedRows.join(',')} have been converted. Skipped.`);
- }
- }
-
- await context.sync();
- });
- }
-
- /** Check if the table contains the necessary columns.
- *** These columns can be in any order within the
- **/
- function isTableValid(items: Excel.TableColumn[]) {
- // Build the column index, search table header
- // Currency - origin currency
- // Price (Currency) - price in origin currency
- // Transaction Date - transaction date
- // Base - home currency
- // Price in Base - price in base currency
- items.forEach((col, idx, arr) => {
- tableSetup[col.name] = idx;
- });
- if (tableSetup['Currency'] === undefined || tableSetup['Price (Currency)'] === undefined || tableSetup['Transaction Date'] === undefined || tableSetup['Base'] === undefined || tableSetup['Price in Base'] === undefined) {
- return false;
- }
- return true;
- }
-
- /** Request currency exchange on specific date **/
- function convertValue(currencyOrig, currencyBase, start, end) {
- // GET https://api.exchangeratesapi.io/latest?symbols=SGD,USD&base=SGD&start_at=2019-10-05&end_at=2019-10-05
- const baseUrl = "https://api.exchangeratesapi.io/latest";
- const query =
- "?base=" + currencyOrig + "&symbols=" + currencyBase + "," + currencyOrig + "&start_at=" + start + "&end_at=" + end;
- return baseUrl + query;
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
- /* Create sample data */
- /* Default header */
- /* "Currency","Price (Currency)","Transaction Date","Base","Price in Base" */
- async function setupSample() {
- await Excel.run(async (context) => {
- context.workbook.worksheets.getItemOrNullObject("Sample").delete();
- const sheet = context.workbook.worksheets.add("Sample");
- const transactionTable = sheet.tables.add("A1:F1", true);
- transactionTable.name = tableName;
- transactionTable.getHeaderRowRange().values = [["Product", "Currency", "Price (Currency)", "Transaction Date", "Base", "Price in Base"]];
- transactionTable.rows.add(null, [
- ["Frames", "MYR", 5000, "2019-10-05", "SGD", null],
- ["Chains", "CNY", 12000, "2019-10-04", "SGD", null]
- ]);
- transactionTable.getRange().format.autofitColumns();
- sheet.activate();
- });
- }
- language: typescript
-template:
- content: |
-
-
Simple Currency Converter
-
-
-
-
Simple currency converter shows how to read data from a transaction table, and uses currency converter API to
- calculate the amount in base currency.
-
The code also performs table validation and identify if the table has predefined headers. You can try to to rearrange the the
- column, and see by yourself!
-
-
-
-
Set up
-
-
-
-
-
Try it out
-
The currency conversion is provided by exchangeratesapi.io which uses
- exchange rate data published by the European Central Bank. Click "Convert"
- `;
- return usageElem;
- }
-
- let sessionInitializing = false;
- async function initializeSceneAsync() {
- for (const key in cachedShapesByPosition) {
- if (cachedShapesByPosition.hasOwnProperty(key)) {
- const shp = cachedShapesByPosition[key];
- shp.delete();
- delete cachedShapesByPosition[key];
- }
- }
- await ctx.sync();
-
- for (let i = 0; i < NUM_ROWS; i++) {
- for (let j = 0; j < NUM_COLS; j++) {
- if (renderPolicy == RENDER_USING_ADD_FILL) {
- let top = i * BLOCK_HEIGHT;
- let left = j * BLOCK_WIDTH;
- let key = top + "-" + left;
-
- let newshp = shapes.addGeometricShape("Rectangle");
- newshp.left = left;
- newshp.top = top;
- newshp.width = BLOCK_WIDTH;
- newshp.height = BLOCK_HEIGHT;
-
- newshp.fill.transparency = 1;
- newshp.fill.foregroundColor = "#000000";
-
- cachedShapesByPosition[key] = newshp;
- }
- }
- }
-
- await ctx.sync();
- sessionInitializing = false;
- }
-
- let throttledRedraw;
- function redraw(session, isPaused, containerElem) {
- containerElem.innerHTML = "";
-
- if (sessionInitializing) {
- return;
- }
-
- let drawingFactory = function(context) {
- return function() {
- drawCoreMovement.apply(context, [session, isPaused, containerElem]);
- };
- };
-
- if (!throttledRedraw) {
- throttledRedraw = _.throttle(drawingFactory(this), TICK_MS / 5, { maxWait: TICK_MS });
- }
-
- throttledRedraw();
- }
-
- async function run(rootelem, containerElem) {
- const session = new coreMovementFunction();
- await initializeSceneAsync();
-
- play();
-
- function play() {
- const intervalHandler = setInterval(function() {
- if (session.tick()) {
- redraw(session, false, containerElem);
- }
- }, TICK_MS);
-
- async function keyHandler(kev) {
- if (kev.shiftKey || kev.altKey || kev.metaKey) {
- return;
- }
-
- let consumed = true;
- let mustpause = false;
- if (kev.keyCode === KEY_ENTER) {
- mustpause = true;
- } else if (kev.keyCode === KEY_R) {
- kev.preventDefault();
- consumed = false;
- sessionInitializing = true;
- session.reset();
- await initializeSceneAsync();
- } else if (kev.keyCode === KEY_LEFT) {
- session.steerLeft();
- } else if (kev.keyCode === KEY_RIGHT) {
- session.steerRight();
- } else if (kev.keyCode === KEY_DOWN) {
- session.steerDown();
- } else if (kev.keyCode === KEY_A) {
- session.rotateLeft();
- } else if (kev.keyCode === KEY_D) {
- session.rotateRight();
- } else if (kev.keyCode === KEY_SPACE) {
- session.letFall();
- } else {
- consumed = false;
- }
-
- if (consumed) {
- kev.preventDefault();
- if (mustpause) {
- rootelem.removeEventListener("keydown", keyHandler);
- clearInterval(intervalHandler);
- pause();
- } else {
- redraw(session, false, containerElem);
- }
- }
- }
-
- rootelem.addEventListener("keydown", keyHandler);
- }
-
- function pause() {
- function keyHandler(kev) {
- if (kev.keyCode == KEY_ENTER) {
- rootelem.removeEventListener("keydown", keyHandler);
- play();
- }
- }
-
- rootelem.addEventListener("keydown", keyHandler);
- redraw(session, true, containerElem);
- }
- }
-
- await run($("#container")[0], $("#sessionPane")[0]);
-
- $("#container").focus();
- $("#focus").show();
- });
- }
-
- /** Default helper for invoking an action and handling errors. */
- async function tryCatch(callback) {
- try {
- await callback();
- } catch (error) {
- $("#setup").show();
- // Note: In a production add-in, you'd want to notify the user through your add-in's UI.
- console.error(error);
- }
- }
-
- function getDefaultBackgroundPicture() {
- return "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";
- }
- language: typescript
-template:
- content: |-
-
-
-
This sample lets you repeatedly stack tetrominos, which are represented by Shapes. Select a background image (or leave blank for the default) and Start!. The controls will then be displayed.
-
-
-
-
Select Background Image
-
-
-
-
-
-
-
-
-
-
Use the Keyboard Focus button if the keyboard controls aren't working (to regain focus on the task pane).