アプリケーション固有の API モデル

この記事では、API モデルを使用して Excel、OneNote、PowerPoint、Visio、Wordでアドインをビルドする方法について説明します。 この説明では、Promise ベースの API の使用に基本的な主要な概念を説明します。

注:

このモデルは、Outlook または Project クライアントではサポートされていません。 共通 API モデルを使用して、これらのアプリケーションを操作します。 フル プラットフォーム可用性のノートについては、「Office アドイン用 Office クライアント アプリケーションとプラットフォームの可用性」を参照してください。

ヒント

このページの例では Excel JavaScript API を使用していますが、この概念は OneNote、PowerPoint、Visio、Word JavaScript API にも適用されます。 さまざまな Office アプリケーションでこれらの概念やその他の概念を使用する方法を示す完全な コード サンプルについては、「Office アドインのコード サンプル」を参照してください。

Promise ベース API の非同期の性質

Office アドインは、Excel などの Office アプリケーション内の Web ビュー コントロール内に表示される Web サイトです。 このコントロールは、Office on Windows などのデスクトップ ベースのプラットフォーム上の Office アプリケーション内に埋め込まれており、Office on the webの HTML iframe 内で実行されます。 パフォーマンスの考慮事項により、Office.js API は、すべてのプラットフォームの Office アプリケーションと同期して対話することはできません。 このため、sync()Office.js 内の API 呼び出しは Office アプリケーションが要求された読み取りまたは書き込み操作を完了したときに解決された Promiseを返します。 また、操作ごとに別個の要求として送信する代わりに、プロパティの設定やメソッドの起動など、複数の操作をキューに登録し、sync()への 1 回の呼び出しでコマンドのバッチとしてそれらを実行することもできます。 次のセクションでは、run() および sync() API を使用してこれを実行する方法について説明します。

*.run 関数

Excel.runOneNote.runPowerPoint.runおよび Word.run Excel、Word、OneNote に対して実行するアクションを指定する関数を実行します。 *.run は Office オブジェクトと対話するために使用できる要求コンテキストを自動的に作成します。 *.runが完了すると、Promose が解決され、実行時に割り当てられたすべてのオブジェクトが自動的に解放されます。

次の例は、Excel.runの使用方法を説明しています。 OneNote、PowerPoint、Visio、Wordでも同じパターンが使用されます。

Excel.run(function (context) {
    // Add your Excel JS API calls here that will be batched and sent to the workbook.
    console.log('Your code goes here.');
}).catch(function (error) {
    // Catch and log any errors that occur within `Excel.run`.
    console.log('error: ' + error);
    if (error instanceof OfficeExtension.Error) {
        console.log('Debug info: ' + JSON.stringify(error.debugInfo));
    }
});

要求コンテキスト

Office アプリケーションとアドインは、さまざまなプロセスで実行されます。 それらは異なるランタイム環境を使用するため、アドインは、ワークシート、範囲、グラフ、表など、Office のオブジェクトにユーザーのアドインを接続するために RequestContext オブジェクトが必要です。 この RequestContext オブジェクトは、*.runを呼び出す際に引数として提供されます。

プロキシ オブジェクト

Promise ベースの API と共にユーザーが宣言して使用する Office JavaScript オブジェクトはプロキシ オブジェクトです。 起動するメソッドや、プロキシ オブジェクトに設定または読み込まれるプロパティは、保留中のコマンドのキューに単純に追加されます。 要求コンテキスト上 (たとえば context.sync()) で sync()メソッドを呼び出すと、キューに入れられたコマンドは Office アプリケーションにディスパッチされて実行されます。 これらの API は、基本的にバッチ中心です。 要求コンテキストに必要なだけ変更内容をキューに登録し、sync() メソッドを呼び出して、キューに入れられたコマンドをバッチで実行することができます。

たとえば、次のコード スニペットでは、ローカル JavaScript Excel.Range オブジェクト、selectedRangeが Excel ワークブック内の選択範囲を参照することを宣言し、そのオブジェクトでいくつかのプロパティを設定します。 selectedRange オブジェクトはプロキシ オブジェクトであるため、設定されたプロパティと、そのオブジェクトに対して呼び出されたメソッドは、ユーザーのアドインが context.sync() を呼び出すまで Excel ドキュメントには反映されません。

const selectedRange = context.workbook.getSelectedRange();
selectedRange.format.fill.color = "#4472C4";
selectedRange.format.font.color = "white";
selectedRange.format.autofitColumns();

作業のヒント: 作成されたプロキシ オブジェクトの数を最小限にする

同じプロキシ オブジェクトを繰り返し作成することは避けるようにします。 代わりに、複数の操作で同じプロキシ オブジェクトが必要な場合は、一度作成して変数に割り当ててから、その変数をコードで使用します。

// BAD: Repeated calls to .getRange() to create the same proxy object.
worksheet.getRange("A1").format.fill.color = "red";
worksheet.getRange("A1").numberFormat = "0.00%";
worksheet.getRange("A1").values = [[1]];

// GOOD: Create the range proxy object once and assign to a variable.
const range = worksheet.getRange("A1");
range.format.fill.color = "red";
range.numberFormat = "0.00%";
range.values = [[1]];

// ALSO GOOD: Use a "set" method to immediately set all the properties
// without even needing to create a variable!
worksheet.getRange("A1").set({
    numberFormat: [["0.00%"]],
    values: [[1]],
    format: {
        fill: {
            color: "red"
        }
    }
});

sync()

要求コンテキストで sync()メソッドを呼び出すと、プロキシ オブジェクトと Officeドキュメント内のオブジェクトの状態が同期されます。 sync() メソッドは、要求コンテキストのキューに登録されたすべてのコマンドを実行し、プロキシ オブジェクトに読み込まれるプロパティの値を取得します。 sync()メソッドは非同期で実行されて Promise を返します。これは、sync() メソッドが完了すると解決されます。

次の例は、ローカル JavaScript proxy オブジェクト (selectedRange) を定義し、そのオブジェクトのプロパティを読み込み、JavaScript の Promises パターンを使用して context.sync() を呼び出し、プロキシ オブジェクトと Excel ドキュメント内のオブジェクトの状態を同期するバッチ関数を示しています。

await Excel.run(async (context) => {
    const selectedRange = context.workbook.getSelectedRange();
    selectedRange.load('address');
    await context.sync();
    console.log('The selected range is: ' + selectedRange.address);
});

前の例では、selectedRange が設定されており、context.sync() が呼び出されると address プロパティが読み込まれます。

sync()が非同期操作である場合、スクリプトが引き続き実行される前に、Promise オブジェクトを返して、sync()の操作が完了するのを確認する必要があります。 TypeScript または ES6+ JavaScript を使用している場合は、Promise を返す代わりに context.sync() の呼び出しをawait にできます。

作業のこつ: 同期呼び出しの数を最小限にする

Excel JavaScript API では、sync() は唯一の非同期操作で、状況によっては遅くなる可能性があり、Excel on the web の場合は特にその傾向があります。 パフォーマンスを最適化するには、sync() を呼び出す前にできるだけ多くの変更をキューイングして、呼び出しの数を最小限にします。 パフォーマンスをsync()で最適化する方法の詳細については、「ループで context.sync メソッドの使用を避ける」をご参照ください。

load()

プロキシ オブジェクトのプロパティを読み取るには、まず Office ドキュメントからプロキシ オブジェクトとデータを入力するためにプロパティを明確に読み込み、context.sync()を呼び出す必要があります。 たとえば、選択範囲を操作するプロキシ オブジェクトを作成してから選択範囲のaddress プロパティを読み取る場合、読み取る前にaddress プロパティを読み込む必要があります。 読み込むプロキシ オブジェクトのプロパティを要求するには、オブジェクトに対して load() メソッドを呼び出し、読み込むプロパティを指定します。 次の例は、myRangeに読み込まれているプロパティ Range.addressを示しています 。

await Excel.run(async (context) => {
    const sheetName = 'Sheet1';
    const rangeAddress = 'A1:B2';
    const myRange = context.workbook.worksheets.getItem(sheetName).getRange(rangeAddress);

    myRange.load('address');
    await context.sync();
      
    console.log (myRange.address);   // ok
    //console.log (myRange.values);  // not ok as it was not loaded

    console.log('done');
});

注:

メソッドのみを呼び出す場合、またはプロキシ オブジェクトのプロパティを設定する場合は、 メソッドを呼び出す load() 必要はありません。 load() メソッドは、プロキシ オブジェクト上でプロパティを読み取る場合のみ必要です。

プロキシ オブジェクトにプロパティを設定する要求やメソッドを呼び出す要求と同様に、プロキシ オブジェクトのプロパティを読み込む要求は、要求コンテキストで保留中のコマンドのキューに追加されます。これは、次回メソッドを呼び出 sync() すと実行されます。 要求コンテキストで必要な数の load() 呼び出しをキューに入れます。

スカラー プロパティとナビゲーション プロパティ

プロパティには、スカラーナビゲーションという 2 つのカテゴリがあります。 スカラー プロパティは、文字列、整数、JSON 構造体などの割り当て可能な型です。 ナビゲーション プロパティは、プロパティを直接割り当てるのではなく、読み取り専用のオブジェクトと、そのフィールドが割り当てられているオブジェクトのコレクションです。 たとえば、Excel.Worksheetのオブジェクトの name メンバーと position メンバーはスカラー プロパティですが、protectiontables はナビゲーション プロパティです。

アドインは、特定のスカラー プロパティを読み込むパスとしてナビゲーション プロパティを使用できます。 次のコードは、ほかの情報を読み込む必要なく、Excel.Range オブジェクトで使用されるフォント名のload コマンドをキューに入れられます。

someRange.load("format/font/name")

パスを詳しく調べることでナビゲーション プロパティのスカラー プロパティを設定できます。 たとえば、someRange.format.font.size = 10;を使用してExcel.Range のフォント サイズを設定できます。 設定前にプロパティを読み込む必要はありません。

オブジェクトの下の「プロパティ」の中には、別のオブジェクトと同じ名前を持つものがあることに注意してください。 例えば、formatExcel.Rangeオブジェクトの下のプロパティですが、format それ自体もオブジェクトです。 そのため、range.load("format")などの呼び出しを行った場合、これは range.format.load() (望ましくない空の空白のステートメントload()) と同等になります。 これを避けるには、コードがオブジェクト ツリー内の "リーフノード" のみをロードするようにしてください。

コレクションからの読み込み

コレクションを操作する場合は、コレクションで を使用 load して、コレクション内のすべてのオブジェクトのプロパティを読み込みます。 そのコレクション内の個々のオブジェクトの場合とまったく同じように使用 load します。

次のサンプル コードは、 name "Sample" ワークシート内のすべてのグラフに対して読み込まれ、ログに記録されるプロパティを示しています。

await Excel.run(async (context) => {
    const sheet = context.workbook.worksheets.getItem("Sample");
    const chartCollection = sheet.charts;

    // Load the name property on every chart in the chart collection.
    chartCollection.load("name");
    await context.sync();

    chartCollection.items.forEach((chart) => {
        console.log(chart.name);
    });
});

通常、コレクションの プロパティは items 引数に load 含まれません。 項目プロパティを読み込む場合、すべての項目が読み込まれます。 ただし、コレクション内の項目をループするが、項目の特定のプロパティを読み込む必要がない場合は、 プロパティがloaditems必要です。

次のサンプル コードは、"Sample" ワークシート内のすべてのグラフに対して設定されているプロパティを示しています name

await Excel.run(async (context) => {
    const sheet = context.workbook.worksheets.getItem("Sample");
    const chartCollection = sheet.charts;

    // Load the items property from the chart collection to set properties on individual charts.
    chartCollection.load("items");
    await context.sync();

    chartCollection.items.forEach((chart, index) => {
        chart.name = `Sample chart ${index}`;
    });
});

パラメーターを指定せずにオブジェクト (またはコレクション) の load() メソッドを呼び出すと、オブジェクトのすべてのスカラー プロパティ (またはコレクション内のオブジェクト) が読み込まれます。 不要なデータを読み込むと、アドインの速度が低下します。 常に読み込むプロパティを明示的に指定する必要があります。

重要

パラメーターのない load ステートメントで返されるデータの量は、サービスのサイズ制限を超える場合があります。 古いアドインのリスクを軽減するために、明示的に要求しない限り load によって返されないプロパティがあります。 次のプロパティは、このような読み込み操作から除外されます。

  • Excel.Range.numberFormatCategories

ClientResult

プリミティブ型を返す、Promise ベースの API 内のメソッドは、load/syncパラダイムと同様のパターンを持っています。 たとえば、Excel.TableCollection.getCount はコレクション内のテーブルの数を取得します。 getCountClientResult<number> を返します。つまり、返されるClientResultvalueプロパティは数値になります。 context.sync() が呼び出されるまで、スクリプトはその値にアクセスできません。

次のコードは、Excel ワークブック内のテーブルの総数を取得し、その数をコンソールに記録します。

const tableCount = context.workbook.tables.getCount();

// This sync call implicitly loads tableCount.value.
// Any other ClientResult values are loaded too.
await context.sync();

// Trying to log the value before calling sync would throw an error.
console.log (tableCount.value);

set()

入れ子になったナビゲーション プロパティを持つオブジェクトのプロパティを設定するのは面倒です。 前述のナビゲーション パスを使用してプロパティを個別に設定する代わりに、Promise ベースの JavaScript API のオブジェクトで使用できる、object.set()メソッドを使用できます。 このメソッドを使用すると、同じ Office.js 型の別のオブジェクト、またはメソッドが呼び出されるオブジェクトのプロパティと同様に構造化されたプロパティを持つ JavaScript オブジェクトを渡すことによって、オブジェクトの複数のプロパティを一度に設定できます。

次のコード サンプルでは、 メソッドを呼び出し、オブジェクト内のプロパティの構造をset()ミラーするプロパティ名と型を持つ JavaScript オブジェクトを渡すことで、範囲のいくつかの書式プロパティをRange設定します。 この例では、範囲 B2:E2 にデータがあると仮定します。

await Excel.run(async (context) => {
    const sheet = context.workbook.worksheets.getItem("Sample");
    const range = sheet.getRange("B2:E2");
    range.set({
        format: {
            fill: {
                color: '#4472C4'
            },
            font: {
                name: 'Verdana',
                color: 'white'
            }
        }
    });
    range.format.autofitColumns();

    await context.sync();
});

一部のプロパティを直接設定できません

書き込み可能であるにもかかわらず、一部のプロパティを設定できません。 これらのプロパティは、1 つのオブジェクトとして設定する必要がある親プロパティの一部です。 これは、親プロパティが特定の論理関係を持つサブプロパティに依存しているからです。 これらの親プロパティは、オブジェクトの個々のサブプロパティを設定するのではなく、オブジェクト全体を設定するためにオブジェクト リテラル表記を使用して設定する必要があります。 その 1 つの例は、PageLayoutにあります。 プロパティは zoom 、次に示すように、単一 の PageLayoutZoomOptions オブジェクトで設定する必要があります。

// PageLayout.zoom.scale must be set by assigning PageLayout.zoom to a PageLayoutZoomOptions object.
sheet.pageLayout.zoom = { scale: 200 };

前の例では、 という値sheet.pageLayout.zoom.scale = 200;を直接割り当てzoomることはできません。 このステートメントは、zoom が読み込まれないので、エラーを発生させます。 zoom が読み込まれるような場合でも、スケール セットは有効化されません。 すべてのコンテキスト操作は zoom上、でアドインのプロキシオブジェクトを更新し、ローカルに設定された値を上書きする場合に発生します。

この動作は、Range.formatなど、ナビゲーション プロパティ とは異なります。 の format プロパティは、次に示すように、オブジェクト ナビゲーションを使用して設定できます。

// This will set the font size on the range during the next `content.sync()`.
range.format.font.size = 10;

読み取り専用の修飾キーを確認することで、サブプロパティを直接設定できないプロパティを識別できます。 読み取り専用プロパティはすべて、読み取り専用以外のサブプロパティを直接設定できます。 PageLayout.zoom のような書き可能なプロパティは、そのレベルのオブジェクトで設定する必要があります。 まとめると、以下のようになります。

  • 読み取り専用プロパティ: ナビゲーション経由でサブプロパティを設定できます。
  • 書き込み可能なプロパティ: サブプロパティをナビゲーションを介して設定することはできません (最初の親オブジェクトの一部として設定する必要があります)。

*OrNullObject メソッドとプロパティ

一部のアクセサリ方法とプロパティでは、目的のオブジェクトが存在しない場合に例外をスローします。 たとえば、ブックに存在しないワークシート名を指定して Excel ワークシートを取得しようとすると、getItem() メソッドは ItemNotFound 例外を返します。 アプリケーション固有のライブラリを使用すると、例外処理コードを必要とせずに、コードがドキュメント エンティティの存在をテストできます。 これは、*OrNullObjectメソッドのバリエーションとプロパティ を使用して行います。 これらのバリエーションは、 isNullObject プロパティが trueに設定されているオブジェクトを返します (指定したアイテムが存在しない場合は、例外をスローしません)。

たとえば、Worksheets などのコレクションで getItemOrNullObject() メソッドを呼び出して、コレクションからのアイテムの取得を試行できます。 getItemOrNullObject() メソッドは、指定された項目が存在する場合はその項目を返し、それ以外の場合は isNullObjectプロパティが trueに設定されているオブジェクトを返します。 コードは、このプロパティを評価して、オブジェクトが存在するかどうかを判断できます。

注:

*OrNullObject のバリエーションは、JavaScript 値nullを返すことはありません。 通常の Office プロキシ オブジェクトを返します。 オブジェクトが表すエンティティが存在しない場合は、オブジェクトの isNullObject プロパティが trueに設定されます。 返されたオブジェクトの null 値または 真偽性はテストしません。 これは、決して nullfalseundefinedではありません。

次のコード サンプルは getItemOrNullObject() メソッドを使用して、"Data" という名前のワークシートの取得を試行します。 その名前のワークシートが存在しない場合は、新しいシートが作成されます。 コードはisNullObjectプロパティを読み込まないことにご注意ください。 Office は、context.syncが呼ばれると、自動的にこのプロパティを読み込みます。ですから、dataSheet.load('isNullObject')のような名前で明示的に読み込む必要はありません。

await Excel.run(async (context) => {
    let dataSheet = context.workbook.worksheets.getItemOrNullObject("Data");
    
    await context.sync();
    
    if (dataSheet.isNullObject) {
        dataSheet = context.workbook.worksheets.add("Data");
    }
    
    // Set `dataSheet` to be the second worksheet in the workbook.
    dataSheet.position = 1;
});

アプリケーションの元に戻すスタック

アプリケーション固有の API が処理されると、アプリケーションの元に戻すスタックがクリアされます。 つまり、アドインによって行われた操作の前に行われた変更を元に戻すことはできません (そのアドインが共通 API のみを使用しているか、ファイルと対話しない場合を除きます)。 アドインによって行われた変更についても同じことが当てはまります。

関連項目