よく使用される jQuery プラグインの 1 つに DataTables があります。 DataTables により、SharePoint と外部 API の両方のデータから強力なデータ概要を簡単に作成できます。
スクリプト エディター Web パーツを使用してビルドされた IT 要求のリスト
DataTables を使用して SharePoint のカスタマイズを SharePoint Framework に移行するプロセスを例示するために、SharePoint リストから取得される IT サポート要求の概要を示す次のソリューションを使用します。
このソリューションは、標準の SharePoint スクリプト エディター Web パーツを使用して構築されます。 カスタマイズで使用されるコードを次に示します。
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://cdn.datatables.net/1.10.15/js/jquery.dataTables.js"></script>
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table id="requests" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>
<script>
// UMD
(function(factory) {
"use strict";
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], function ($) {
return factory( $, window, document );
});
}
else if (typeof exports === 'object') {
// CommonJS
module.exports = function (root, $) {
if (!root) {
root = window;
}
if (!$) {
$ = typeof window !== 'undefined'
? require('jquery')
: require('jquery')( root );
}
return factory($, root, root.document);
};
} else {
// Browser
factory(jQuery, window, document);
}
}
(function($, window, document) {
$.fn.dataTable.render.moment = function (from, to, locale) {
// Argument shifting
if (arguments.length === 1) {
locale = 'en';
to = from;
from = 'YYYY-MM-DD';
} else if (arguments.length === 2) {
locale = 'en';
}
return function (d, type, row) {
var m = window.moment(d, from, locale, true);
// Order and type get a number value from Moment, everything else
// sees the rendered value
return m.format(type === 'sort' || type === 'type' ? 'x' : to);
};
};
}));
</script>
<script>
$(document).ready(function() {
$('#requests').DataTable({
'ajax': {
'url': "../_api/web/lists/getbytitle('IT Requests')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title",
'headers': { 'Accept': 'application/json;odata=nometadata' },
'dataSrc': function(data) {
return data.value.map(function(item) {
return [
item.ID,
item.BusinessUnit,
item.Category,
item.Status,
new Date(item.DueDate),
item.AssignedTo.Title
];
});
}
},
columnDefs: [{
targets: 4,
render: $.fn.dataTable.render.moment('YYYY/MM/DD')
}]
});
});
</script>
最初に、カスタマイズで使用するライブラリとして、jQuery、DataTables、Moment.js を読み込みます。
次に、データを表示するために使用するテーブルの構造を指定します。
テーブルを作成すると、Moment.js プラグインが DataTables にラップされるため、テーブルに表示される日付の書式設定が可能になります。
最後に、DataTables を使用して IT サポート要求のリストが読み込まれ、表示されます。 データは AJAX によって SharePoint リストから読み込まれます。
DataTables を使用するおかげで、エンド ユーザーは追加の開発作業の手間をかけずに、結果を簡単にフィルター、並べ替え、ページ編成できる強力なソリューションを手に入れることになります。
スクリプト エディター Web パーツから SharePoint Framework に IT 要求概要ソリューションを移行する
このカスタマイズを SharePoint Framework に移行することで、よりユーザー フレンドリな構成や、ソリューションの一元管理など、数多くのメリットが得られます。 次に、ソリューションを SharePoint Framework に移行する方法を、順を追って示します。 まず、オリジナルのコードの変更を最小限に抑える形で、ソリューションを SharePoint Framework に移行します。 その後、ソリューションのコードを TypeScript に変換し、開発時のタイプ セーフな機能を利用できるようにします。
注:
移行のさまざまな段階におけるプロジェクトのソース コードは、「チュートリアル: スクリプト エディター Web パーツを使用してビルドした jQuery および DataTables ソリューションを SharePoint Framework に移行する」から入手できます。
新しい SharePoint Framework プロジェクトを作成する
まず、プロジェクト用の新しいフォルダーを作成します。
md datatables-itrequests
プロジェクト フォルダーに移動します。
cd datatables-itrequests
プロジェクト フォルダーで SharePoint Framework Yeoman ジェネレーターを実行して、新しい SharePoint Framework プロジェクトをスキャホールディングします。
yo @microsoft/sharepoint
プロンプトが表示されたら、以下の値を入力します (以下で省略されたすべてのプロンプトに対して既定のオプションを選択します)。
- ソリューション名は何ですか?: datatables-itrequests
- どの種類のクライアント側コンポーネントを作成しますか?: Web パーツ
- Web パーツ名は何ですか?: IT requests
- Web パーツで何を行いますか?: IT サポート要求の概要を表示する
- どのフレームワークを使用しますか?: JavaScript フレームワークなし
コード エディターでプロジェクト フォルダーを開きます。 このチュートリアルでは、Visual Studio Code を使用します。
JavaScript ライブラリを読み込む
スクリプト エディター Web パーツを使用して構築された元のソリューションと同様に、まず、ソリューションで必要な JavaScript ライブラリを読み込む必要があります。 SharePoint Framework通常、これは 2 つの手順で構成されます。ライブラリの読み込み元の URL を指定し、コードでライブラリを参照します。
ライブラリの読み込み元となる URL を指定します。 コード エディターで、./config/config.json ファイルを開き、
externals
セクションを次のように変更します。{ // .. "externals": { "jquery": { "path": "https://code.jquery.com/jquery-1.12.4.min.js", "globalName": "jQuery" }, "datatables.net": { "path": "https://cdn.datatables.net/1.10.15/js/jquery.dataTables.min.js", "globalName": "jQuery", "globalDependencies": [ "jquery" ] }, "moment": "https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.27.0/moment.min.js" }, // .. }
これには、次の 2 つの目的があります。
- SharePoint Framework ビルド ツールチェーンが Web パーツ向けのバンドルを作成するとき、これら 3 つのパッケージに対する
import
またはrequire
ステートメントをすべて無視し、ソースをバンドルに含めません。 これらがない場合、webpack (バンドルを作成するのに使用するツール) は結果として生成される SPFx コンポーネントのバンドルにこれらの JavaScript ライブラリをインポートします。 - SharePoint Framework ビルド ツールチェーンはこれら 3 つのパッケージをコンポーネントのマニフェストに依存関係として追加します。 これにより、SharePoint Framework のモジュール ローダーは、コンポーネントのバンドルを読み込む前にこれらのライブラリをページに確実に読み込みます。
注:
SharePoint Framework プロジェクトでの外部ライブラリの参照の詳細については、「外部ライブラリを SharePoint のクライアント側 Web パーツに追加する」を参照してください。
- SharePoint Framework ビルド ツールチェーンが Web パーツ向けのバンドルを作成するとき、これら 3 つのパッケージに対する
./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開いて、最後の
import
ステートメントの後に以下を追加します。import 'jquery'; import 'datatables.net'; import 'moment';
データ テーブルの定義
元のソリューションと同様、次の手順ではデータの表示に使用するテーブルの構造を定義します。
コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開き、render()
メソッドを次のように変更します。
export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> {
public render(): void {
this.domElement.innerHTML = `
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" />
<table id="requests" class="display ${styles.itRequests}" cellspacing="0" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Business unit</th>
<th>Category</th>
<th>Status</th>
<th>Due date</th>
<th>Assigned to</th>
</tr>
</thead>
</table>`;
}
// ...
}
DataTables 用の Moment.js プラグインの登録
次の手順では、DataTables 用の Moment.js プラグインを定義し、テーブル内の日付を書式設定できるようにします。
./src/webparts/itRequests フォルダーに、moment-plugin.js という名前の新しいファイルを作成して、次のコードを貼り付けます。
// UMD ( function (factory) { "use strict"; if (typeof define === 'function' && define.amd) { // AMD define(['jquery'], function ($) { return factory($, window, document); }); } else if (typeof exports === 'object') { // CommonJS module.exports = function (root, $) { if (!root) { root = window; } if (!$) { $ = typeof window !== 'undefined' ? require('jquery') : require('jquery')(root); } return factory($, root, root.document); }; } else { // Browser factory(jQuery, window, document); } } (function ($, window, document) { $.fn.dataTable.render.moment = function (from, to, locale) { // Argument shifting if (arguments.length === 1) { locale = 'en'; to = from; from = 'YYYY-MM-DD'; } else if (arguments.length === 2) { locale = 'en'; } return function (d, type, row) { var moment = require('moment'); var m = moment(d, from, locale, true); // Order and type get a number value from Moment, everything else // sees the rendered value return m.format(type === 'sort' || type === 'type' ? 'x' : to); }; }; }) );
Web パーツがプラグインを読み込むためには、新しく作成した moment-plugin.js ファイルを参照する必要があります。 コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開いて、最後の
import
ステートメントの後に以下を追加します。import './moment-plugin';
DataTables を初期化し、データを読み込む
最後の手順では、データ テーブルを初期化して SharePoint からデータを読み込むコードを含めます。
./src/webparts/itRequests フォルダーに、script.js という名前の新しいファイルを作成して、次のコードを貼り付けます。
$(document).ready(function () { $('#requests').DataTable({ 'ajax': { 'url': "../../_api/web/lists/getbytitle('IT Requests')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title", 'headers': { 'Accept': 'application/json;odata=nometadata' }, 'dataSrc': function (data) { return data.value.map(function (item) { return [ item.ID, item.BusinessUnit, item.Category, item.Status, new Date(item.DueDate), item.AssignedTo.Title ]; }); } }, columnDefs: [{ targets: 4, render: $.fn.dataTable.render.moment('YYYY/MM/DD') }] }); });
注:
$select
および $expend
パラメーターには、必ず列の内部名 (つまり静的な名前) を使用してください。
Web パーツでこのファイルを参照するには、コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開き、
render()
メソッドの最後にrequire('./script');
を追加します。render()
メソッドは、次のようになります。export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> { public render(): void { this.domElement.innerHTML = ` <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" /> <table id="requests" class="display ${styles.itRequests}" cellspacing="0" width="100%"> <thead> <tr> <th>ID</th> <th>Business unit</th> <th>Category</th> <th>Status</th> <th>Due date</th> <th>Assigned to</th> </tr> </thead> </table>`; require('./script'); } // ... }
Web パーツが予期したとおりに機能することを確認するため、コマンド ラインで次のコマンドを実行します。
gulp serve --nobrowser
Web パーツはそのデータを SharePoint から読み込むので、ホストされている SharePoint Framework ワークベンチを使用して Web パーツをテストする必要があります。 https://{your-tenant-name}.sharepoint.com/_layouts/workbench.aspx に移動し、Web パーツをキャンバスに追加します。 これで、DataTables jQuery プラグインを使用すると IT 要求が表示されるはずです。
Web パーツのプロパティを使用して Web パーツを構成するためのサポートを追加する
前の手順では、スクリプト エディター Web パーツから SharePoint Framework に IT 要求ソリューションを移行しました。 ソリューションは既に想定どおりに機能していますが、SharePoint Framework の利点は何も活用されていません。 IT 要求の読み込み元であるリストの名前はコードに含まれており、そのコード自体はプレーンな JavaScript であり、そのリファクタリングは TypeScript よりも困難です。
次の手順では、データの読み込み元であるリストの名前をユーザーが指定できるように、既存のソリューションを拡張する方法について説明します。 その後、コードを TypeScript に変換し、そのタイプ セーフな機能を利用できるようにします。
リストの名前を格納するための Web パーツ プロパティを定義する
IT 要求の読み込み元のリスト名を格納するための Web パーツ プロパティを定義します。 コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.manifest.json ファイルを開き、既定の
description
プロパティの名前をlistName
に変更し、その値をクリアします。マニフェスト内の変更を反映するよう Web パーツ プロパティ インターフェイスを更新します。 コード エディターで ./src/webparts/itRequests/IItRequestsWebPartProps.ts ファイルを開き、その内容を次のように変更します。
export interface IItRequestsWebPartProps { listName: string; }
listName
プロパティの表示ラベルを更新します。 ./src/webparts/itRequests/loc/mystrings.d.ts ファイルを開き、その内容を次のように変更します。declare interface IItRequestsStrings { PropertyPaneDescription: string; BasicGroupName: string; ListNameFieldLabel: string; } declare module 'itRequestsStrings' { const strings: IItRequestsStrings; export = strings; }
./src/webparts/itRequests/loc/en-us.js ファイルを開き、その内容を次のように変更します。
define([], function() { return { "PropertyPaneDescription": "IT Requests settings", "BasicGroupName": "Data", "ListNameFieldLabel": "List name" } });
新しく定義したプロパティを使用するよう Web パーツを更新します。 コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開き、
getPropertyPaneConfiguration()
メソッドを次のように変更します。export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> { // ... protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { return { pages: [{ header: { description: strings.PropertyPaneDescription }, groups: [{ groupName: strings.BasicGroupName, groupFields: [ PropertyPaneTextField('listName', { label: strings.ListNameFieldLabel }) ] }] }] }; } protected get disableReactivePropertyChanges(): boolean { return true; } }
ユーザーがリストの名前を入力しているときに Web パーツが再度読み込まないようにするため、disableReactivePropertyChanges()
メソッドを追加して戻り値を true
に設定することにより、非反応性のプロパティ ウィンドウを使用するように Web パーツを設定しました。
データの読み込み元として設定したリスト名を使用する
最初に、データの読み込み元となるリストの名前が REST クエリに埋め込まれました。 これでユーザーがこの名前を構成できるようになり、構成された値はデータの読み込み前に REST クエリに挿入される必要があります。 そうするための最も簡単な方法は、script.js ファイルの内容をメインの Web パーツ ファイルに移動することです。
コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開き、
render()
メソッドを次のように変更します。var $: any = (window as any).$; export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> { public render(): void { this.domElement.innerHTML = ` <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" /> <table class="display ${styles.itRequests}" cellspacing="0" width="100%"> <thead> <tr> <th>ID</th> <th>Business unit</th> <th>Category</th> <th>Status</th> <th>Due date</th> <th>Assigned to</th> </tr> </thead> </table>`; $(document).ready(() => { $('table', this.domElement).DataTable({ 'ajax': { 'url': `../../_api/web/lists/getbytitle('${escape(this.properties.listName)}')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title`, 'headers': { 'Accept': 'application/json;odata=nometadata' }, 'dataSrc': function (data) { return data.value.map(function (item) { return [ item.ID, item.BusinessUnit, item.Category, item.Status, new Date(item.DueDate), item.AssignedTo.Title ]; }); } }, columnDefs: [{ targets: 4, render: $.fn.dataTable.render.moment('YYYY/MM/DD') }] }); }); } // ... }
script.js ファイルからコードを参照する代わりに、その内容はすべて Web パーツの
render
メソッドの一部になります。 REST クエリでは、リストの固定名をlistName
プロパティの値と置き換えることができます。このプロパティはユーザーが構成したリストの名前を保持するものです。 値を使用する前に、lodash のescape
関数を使用してエスケープし、スクリプトの挿入を禁止します。この時点では、コードの大部分はまだプレーンな JavaScript で記述されています。
$
jQuery 変数によるビルドの問題を回避するため、クラス定義の前にこれをany
型として定義する必要がありました。 後でコードを TypeScript に変換するときに、これを正しい型定義と置き換えます。script.js ファイルのコンテンツをメインの Web パーツ ファイルに移動したので、script.js は不要になるためプロジェクトから削除できます。
Web パーツが予期したとおりに機能することを確認するため、コマンド ラインで次のように実行します。
gulp serve --nobrowser
ホストされているワークベンチに移動し、キャンバスに Web パーツを追加します。 Web パーツのプロパティ ウィンドウを開き、IT 要求が含まれているリスト名を指定します。その後、[適用] ボタンを選択して変更を確認します。
これで、Web パーツに表示される IT 要求を確認できるはずです。
プレーンな JavaScript コードを TypeScript に変換する
プレーンな JavaScript ではなく TypeScript を使用すると、さまざまなメリットがあります。 TypeScript のほうが管理およびリファクタリングが簡単なだけでなく、エラーを早期に把握することもできます。 次の手順では、元の JavaScript コードを TypeScript に変換する方法について説明します。
使用しているライブラリに型定義を追加する
正しく機能するには、TypeScript には、プロジェクトで使用されるさまざまなライブラリの型定義が必要です。 型定義は、多くの場合、名前空間の @types npm パッケージとして配布されます。
コマンド ラインで次のように実行して、JQuery と DataTables の型定義をインストールします。
npm install @types/jquery@1.10.34 @types/datatables.net@1.10.15 --save-dev --save-exact
ヒント
この例では、インストールしようとしている NPM パッケージの正確なバージョンを指定しています。 これにより NPM は、jQuery とプロジェクトで使用しているデータベース ライブラリと互換性がある型宣言パッケージを確実にインストールします。
--save-dev
引数はこれら 2 つのパッケージへの参照を package.json ファイルのdevDependencies
コレクションに保存するように NPM に指示します。 TypeScript 宣言は開発時にのみ必要なので、dependencies
コレクションには必要ありません。--save-exact
引数は、package.json ファイルの特定のバージョンに参照を追加し、最新のバージョンへの自動アップグレードを有効にする表記を追加しないように NPM に指示します。Moment.js の型定義は Moment.js パッケージとともに配布されます。 URL から Moment.js を読み込んでいる場合でも、その型を使用するためにはプロジェクトに Moment.js パッケージをインストールする必要があります。
コマンド ラインで次のように実行し、Moment.js パッケージをインストールします。
npm install moment@2.27.0 --save-exact
パッケージ参照を更新する
インストールした型定義の型を使用するには、ライブラリの参照方法を変更する必要があります。
コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開き、
import 'jquery';
ステートメントを次のように変更します。import * as $ from 'jquery';
$
を jQuery として定義したので、今度は以前に追加した$
のローカル定義を削除できます。var $: any = (window as any).$;
メインの Web パーツ ファイルを TypeScript に更新する
プロジェクトにインストールされているすべてのライブラリの型定義を取得したため、プレーンな JavaScript コードから TypeScript への変換を開始できます。
SharePoint リストから取得した IT 要求情報へのインターフェイスを定義します。 コード エディターで ./src/webparts/itRequests/ItRequestsWebPart.ts ファイルを開き、Web パーツ クラスの直前に次のコード スニペットを追加します。
interface IRequestItem { ID: number; BusinessUnit: string; Category: string; Status: string; DueDate: string; AssignedTo: { Title: string; }; }
次に、Web パーツ クラスで
render()
メソッドを次のように変更します。export default class ItRequestsWebPart extends BaseClientSideWebPart<IItRequestsWebPartProps> { public render(): void { this.domElement.innerHTML = ` <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.15/css/jquery.dataTables.min.css" /> <table class="display ${styles.itRequests}" cellspacing="0" width="100%"> <thead> <tr> <th>ID</th> <th>Business unit</th> <th>Category</th> <th>Status</th> <th>Due date</th> <th>Assigned to</th> </tr> </thead> </table>`; $('table', this.domElement).DataTable({ 'ajax': { 'url': `../../_api/web/lists/getbytitle('${escape(this.properties.listName)}')/items?$select=ID,BusinessUnit,Category,Status,DueDate,AssignedTo/Title&$expand=AssignedTo/Title`, 'headers': { 'Accept': 'application/json;odata=nometadata' }, 'dataSrc': (data: { value: IRequestItem[] }): any[][] => { return data.value.map((item: IRequestItem): any[] => { return [ item.ID, item.BusinessUnit, item.Category, item.Status, new Date(item.DueDate), item.AssignedTo.Title ]; }); } }, columnDefs: [{ targets: 4, render: ($.fn.dataTable.render as any).moment('YYYY/MM/DD') }] }); } // ... }
これで、AJAX 要求で SharePoint リストからデータがどのように取得されるかが型定義され、プロパティを DataTables への配列に渡すとき、正しいプロパティを参照しているかどうかを確認することができます。 DataTables でテーブルの行を表示するときに使用するデータ構造は複合型の配列であるため、簡素化のために
any[]
として定義されています。dataSrc
プロパティ内で返されるデータが DataTables の内部で使用されるため、このコンテキストではany
型の使用は悪くありません。render()
メソッドの更新では、次の 2 つの変更も加えています。 まず、テーブルからid
属性を削除しました。 これにより、ページ上で同じ Web パーツの複数のインスタンスを配置できるようになります。 また、$(document).ready()
関数への参照も削除しました。これはデータ テーブルを表示する要素の DOM が DataTables 開始コードの前に設定されているために不要になりました。
Moment.js DataTables プラグインを TypeScript に更新する
TypeScript に変換する必要のあるソリューションの最後の部分は、Moment.js DataTables プラグインです。
./src/webparts/itRequests/moment-plugin.js ファイルの名前を ./src/webparts/itRequests/moment-plugin.ts に変更すると、TypeScript コンパイラで処理されるようになります。
コード エディターで moment-plugin.ts ファイルを開き、その内容を次のように置き換えます。
import * as $ from 'jquery'; import * as moment from 'moment'; /* tslint:disable:no-function-expression */ ($.fn.dataTable.render as any).moment = function (from: string, to: string, locale: string): (d: any, type: string, row: any) => string { /* tslint:enable */ // Argument shifting if (arguments.length === 1) { locale = 'en'; to = from; from = 'YYYY-MM-DD'; } else if (arguments.length === 2) { locale = 'en'; } return (d: any, type: string, row: any): string => { let m: moment.Moment = moment(d, from, locale, true); // Order and type get a number value from Moment, everything else // sees the rendered value return m.format(type === 'sort' || type === 'type' ? 'x' : to); }; };
jQuery および Moment.js への参照の読み込みから開始し、対応する変数が参照する内容を TypeScript に通知します。 次に、プラグイン関数を定義します。 TypeScript では通常、関数にアロー表記を使用します (
=>
)。 ただし、この場合はarguments
プロパティにアクセスする必要があるため、通常の関数定義を使用する必要があります。 アロー表記を使用していないという警告が TSLint から報告されないようにするには、関数定義についてno-function-expression
ルールを明示的に無効にすることができます。すべてが予期したとおりに機能することを確認するため、コマンド ラインで次のコマンドを実行します。
gulp serve --nobrowser
ホストされているワークベンチに移動し、キャンバスに Web パーツを追加します。 何も変更されていないように見えますが、新しいコード ベースは TypeScript とその型定義を使用しており、ソリューションを維持できるようになっています。