0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Excel Web Add-inからJSONPをする

Last updated at Posted at 2019-10-31

0. todo

  • デプロイの方法...はJSONPではなくJSONとして実装した場合の方が面倒になるので、そちらの記事で書くことにします。ということで、この記事は完了とします。

1. 準備、環境

1.1 Visual Studio

筆者はCommunity Editionを使用。他のバージョンについては未検証

1.2 Excel

筆者は Office365 ProPlusを使用。Excel Web Add-inはExcelのバージョンによりAPIレベルが設定されており、低いとほとんど何もできないです。365だと何も考えずにやれますが、最低でも2016、推奨2019。

1.3 Webサーバ

筆者はnode.jsを使用。とりあえずはスタティックなデータを送るデモなのでなんでも良いです。実用システムならJavaScript(JSONではない)を動的に生成することになります。

2. Quick Start

2.1 Visual Studio のWizardでプロジェクトを作成

詳細は割愛。ほとんど何も考えずにはいはいでExcelWebAddin1というプロジェクトができあがります(スクショでは2になっていますが)。とりあえず、そのまま動かしてみてください。

JDAM-2019-10-23-16-37-35.png

JDAM-2019-10-23-16-37-51.png

JDAM-2019-10-23-16-38-04.png

JDAM-2019-10-23-16-38-58.png

JDAM-2019-10-23-16-39-26.png

JDAM-2019-10-23-16-39-50.png

2.2 WebサーバにJavaScriptを置く

JSONPでは、サーバが供給するJavaScriptのコードをクライアントのコンテキストで実行することになります。今回は、2x2の乱数のマトリックスを作って関数を呼ぶようにしました。

test.js
(function() {
    var values = [
        [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000)],
        [Math.floor(Math.random() * 1000), Math.floor(Math.random() * 1000)]
    ];
    jsonp_func(values);
})();

2.3 JSONPを組込む

【強調表示!】ボタンを押すと、test.jsが生成した2x2の乱数マトリックスをA1:B2にフィルするようにしてみました。

Wizardが吐いたHome.jsにJSONPを追加してください。

Home.js
var jsonp_func;                      // 追加 #1

(function () {
// 略
    Office.initialize = function (reason) {
// 略
            // 強調表示ボタンのクリック イベント ハンドラーを追加します。
            $('#highlight-button').click(hightlightHighestValue);

            jsonp_func = get_data;  // 追加 #2
        });
    };

    function call_jsonp() {         // 追加 #3
        const id = "get-data-script";
        var s = document.getElementById(id);
        if (s) {
            s.parentElement.removeChild(s);
        }
        s = document.createElement("script");
        s.src = encodeURI('<<サーバからtest.jsをダウンロードできるURL>>?ts=' + Date.now());
        s.id = id;
        document.getElementsByTagName('head')[0].appendChild(s);
    }

    function get_data(values) {    // 追加 #4
        Excel.run(function (ctx) {
            var sheet = ctx.workbook.worksheets.getActiveWorksheet();
            sheet.getRange("A1:B2").values = values;
            return ctx.sync();
        })
        .catch(errorHandler);
    }
 
    function hightlightHighestValue() {
        call_jsonp();             // 追加 #5
// 略
    }
// 略
})();

3. 解説

3.1 JSONPとしての呼び出し

Home.js: call_jsonp(); // 追加 #5

  • JSONPを呼びだすところ。

Home.js: function call_jsonp() { // 追加 #3

  • JSONPの実体
  • JSONPは、DOMにおいて、scriptエレメントが生成され、src属性が設定されると、JavaScriptのコードをどこかから(どこでもよい)をダウンロードし、(おおむね)即座に実行するという仕組みのようです。
  • Visual Studioのデバッガ上でステップ実行すると、src属性がセットされたタイミングでサーバからGETしています。ただし、それはデバッガでステップ実行しているからだと思いますので、実際のタイミングにあまり仮定を置くのは危険です。
  • ちなみに、scriptエレメント再利用してsrc属性の再設定だけで呼び出しが発生するかを試しましたが、呼び出されませんでした。
  • src属性に(とりあえず)タイムスタンプのQUERY_STRINGを付け加えています。これは、src属性のURIが呼び出しごとに全く同じだと、新たに生成したscriptエレメントに設定しても、ダウンロードが発生しないためのworkaroundです。URIが呼出毎に変化すればタイムスタンプでもカウンターでも乱数でも何でも良いはずです。
  • 生成したscriptエレメントは、次回の呼び出しの際に外して、新たに別のscriptエレメントを生成するようにしています。これが必要かどうかは不明です。JavaScriptでは参照が無くなるとオブジェクトは消えますが、scriptエレメントはDOMオブジェクトですので、念のため増殖しないようにしています。

3.2 JSONPで得られたデータを取り込むための仕組み

Home.js: var jsonp_func; // 追加 #1

  • 生成されたscriptエレメントの中から実行される関数はページとしてのグローバルスコープに無ければなりませんので、変数宣言だけしておきます。

Home.js: jsonp_func = get_data; // 追加 #2

  • 関数の実体を設定します。

Home.js: function get_data(values) { // 追加 #4

  • 生成されたscriptエレメントの中から呼び出され、サーバからのデータを受けとる関数の実体
  • データは引数として渡されます。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?