アプリケーション カスタマイザーからページ プレースホルダーを使用する (Hello World パート 2)

アプリケーション カスタマイザーは、ビジネス上および機能上の要件に基づいて変更できる、SharePoint ページ上の既知の場所へのアクセスを提供します。 たとえば、SharePoint Online のすべてのページでレンダリングされる、ヘッダーとフッターの動的なエクスペリエンスを作成できます。

このモデルは、カスタム JavaScript によりページのエクスペリエンスを変更するために、Site または Web オブジェクトで UserCustomAction コレクションを使用するのと似ています。 SharePoint Framework (SPFx) 拡張機能の主な違いは、SharePoint Online で HTML/DOM 構造に変更を加えた場合、ページ要素が変更されない点です。

この記事は、ページ プレースホルダーを活用するために Hello World 拡張機能を拡張する方法について説明します。

Microsoft 365 プラットフォーム コミュニティ (PnP) YouTube チャンネルのビデオを見て、これらの手順に従うこともできます。

ページ プレースホルダーへのアクセス

アプリケーション カスタマイザー拡張機能は、 サイトWebおよびリスト スコープでサポートされています。 アプリケーション カスタマイザーが SharePoint テナント内で登録される場所と方法を決定することにより、スコープを制御できます。

注:

Application Customizer の機能 XML ベースの登録は、Web レベルまたはリスト レベルでのみサポートされます。 ただし、 拡張機能のテナント全体のデプロイ を使用するか、アプリケーション カスタマイザーをオブジェクトのコレクションに UserCustomAction 関連付けることによって、アプリケーション カスタマイザーをより広くアクティブ化 Site できます。

スコープにアプリケーション カスタマイザーが存在し、レンダリングされている場合、次のメソッドを使用してプレースホルダーにアクセスすることができます。

// Handling the Bottom placeholder
if (!this._bottomPlaceholder) {
  this._bottomPlaceholder =
    this.context.placeholderProvider.tryCreateContent(
      PlaceholderName.Bottom,
      { onDispose: this._onDispose });
...
}

プレースホルダー オブジェクトを取得した後は、エンド ユーザーに何が表示されるかについて完全に制御できます。

既知のプレースホルダーのリクエストに、対応する既知の識別子を使用していることに注目してください。 この場合、コードは列挙型の オプションを使用 Bottom してページのフッター セクションに PlaceholderName アクセスしています。

カスタムの HTML 要素を追加することにより、アプリケーション カスタマイザーを変更して、プレースホルダーにアクセスして変更する

  1. SPFabricCore.scss からのインポートを有効にするには、@microsoft/sp-office-ui-fabric-core パッケージをインストールします。 これは、プレース ホルダーのレンダリング スタイルを定義するために使用します。

    npm install @microsoft/sp-office-ui-fabric-core
    
  2. ./src/extensions/helloWorld/AppCustomizer.module.scss という名前の新しいファイルを作成します。

  3. AppCustomizer.module.scss を次のように更新します。

    注:

    以下のものは、ヘッダーとフッターの各プレースホルダーについて HTML 出力で使用される各スタイルです。

    @import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
    
    .app {
      .top {
          height:60px;
          text-align:center;
          line-height:2.5;
          font-weight:bold;
          display: flex;
          align-items: center;
          justify-content: center;
          background-color: $ms-color-themePrimary;
          color: $ms-color-white;
    
      }
    
      .bottom {
          height:40px;
          text-align:center;
          line-height:2.5;
          font-weight:bold;
          display: flex;
          align-items: center;
          justify-content: center;
          background-color: $ms-color-themePrimary;
          color: $ms-color-white;
      }
    }
    
  4. Visual Studio Code (または任意の IDE) で 、./src/extensions/helloWorld/HelloWorldApplicationCustomizer.ts を開きます。

  5. PlaceholderContent import ステートメントを次のように更新して、@microsoft/sp-application-base から import ステートメントに と PlaceholderName を追加します。

    import {
      BaseApplicationCustomizer,
      PlaceholderContent,
      PlaceholderName
    } from '@microsoft/sp-application-base';
    

    また、ファイルの先頭の strings のインポートの後に次の各 import ステートメントも追加します。

    import styles from './AppCustomizer.module.scss';
    import { escape } from '@microsoft/sp-lodash-subset';
    

    関数を使用 escape して、Application Customizer プロパティをエスケープします。 次の手順で出力用のスタイル定義を作成します。

    注:

    上のコード スニペットに貼り付けた後、Visual Studio Code を使用するとエラーが表示される場合があります。 これらのエラーは、scss ファイルがクラスにコンパイルされるときにソリューションをビルドした後に消えます。

  6. HelloWorldApplicationCustomizer.ts ファイルで、次のようにインターフェイスをIHelloWorldApplicationCustomizerProperties更新して、ヘッダーとフッターの特定のプロパティを追加します。

    注:

    アプリケーション カスタマイザーが JSON 入力を使用する ClientSideComponentProperties 場合は、オブジェクトに BaseExtension.properties 逆シリアル化されます。 インターフェイスを定義してそのオブジェクトを記述することができます。

    export interface IHelloWorldApplicationCustomizerProperties {
      Top: string;
      Bottom: string;
    }
    
  7. クラス内に次のプライベート変数を HelloWorldApplicationCustomizer 追加します。 このシナリオでは、これらを onRender() メソッド内のローカル変数にすることもできますが、他のオブジェクトと共有したい場合はプライベート変数として定義します。

    export default class HelloWorldApplicationCustomizer
      extends BaseApplicationCustomizer<IHelloWorldApplicationCustomizerProperties> {
    
      // These have been added
      private _topPlaceholder: PlaceholderContent | undefined;
      private _bottomPlaceholder: PlaceholderContent | undefined;
    
      // ...
    }
    
  8. onInit() メソッド コードを次のように更新します。

    public onInit(): Promise<void> {
      Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);
    
      // Wait for the placeholders to be created (or handle them being changed) and then
      // render.
      this.context.placeholderProvider.changedEvent.add(this, this._renderPlaceHolders);
    
      return Promise.resolve();
    }
    
  9. 新しい _renderPlaceHolders() のプライベート メソッドを次のコードで作成します。

    private _renderPlaceHolders(): void {
      console.log("HelloWorldApplicationCustomizer._renderPlaceHolders()");
      console.log(
        "Available placeholders: ",
        this.context.placeholderProvider.placeholderNames
          .map(name => PlaceholderName[name])
          .join(", ")
      );
    
      // Handling the top placeholder
      if (!this._topPlaceholder) {
        this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(
          PlaceholderName.Top,
          { onDispose: this._onDispose }
        );
    
        // The extension should not assume that the expected placeholder is available.
        if (!this._topPlaceholder) {
          console.error("The expected placeholder (Top) was not found.");
          return;
        }
    
        if (this.properties) {
          let topString: string = this.properties.Top;
          if (!topString) {
            topString = "(Top property was not defined.)";
          }
    
          if (this._topPlaceholder.domElement) {
            this._topPlaceholder.domElement.innerHTML = `
            <div class="${styles.app}">
              <div class="${styles.top}">
                <i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(
                  topString
                )}
              </div>
            </div>`;
          }
        }
      }
    
      // Handling the bottom placeholder
      if (!this._bottomPlaceholder) {
        this._bottomPlaceholder = this.context.placeholderProvider.tryCreateContent(
          PlaceholderName.Bottom,
          { onDispose: this._onDispose }
        );
    
        // The extension should not assume that the expected placeholder is available.
        if (!this._bottomPlaceholder) {
          console.error("The expected placeholder (Bottom) was not found.");
          return;
        }
    
        if (this.properties) {
          let bottomString: string = this.properties.Bottom;
          if (!bottomString) {
            bottomString = "(Bottom property was not defined.)";
          }
    
          if (this._bottomPlaceholder.domElement) {
            this._bottomPlaceholder.domElement.innerHTML = `
            <div class="${styles.app}">
              <div class="${styles.bottom}">
                <i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(
                  bottomString
                )}
              </div>
            </div>`;
          }
        }
      }
    }
    

    このコードについては、次の点に注意してください。

    • this.context.placeholderProvider.tryCreateContent を使用してプレースホルダーにアクセスします。
    • 拡張コードでは、予期されるプレースホルダーが使用可能であると想定しないでください。
    • コードは、Top および Bottom と呼ばれるカスタム プロパティを想定します。 プロパティが存在する場合、それらはプレースホルダー内でレンダリングされます。
    • 上部および下部のプレースホルダーへのコード パスがどちらもほとんど同一であることに注目してください。 唯一の違いは、使用されている変数とスタイル定義です。
    • スタイル シートで定義されているクラス名を直接使用することはできますが、推奨されません。 styles 変数で定義されたスタイル シート参照がコード内にない場合、そのスタイル シートはページに追加されません。 これは、使用されていない参照がビルド処理中に削除されるためです。
  10. 次のメソッドを _renderPlaceHolders() メソッドの後に追加します。 この例では、拡張機能がページから削除されるときに、コンソール メッセージを出力するだけです。

    private _onDispose(): void {
      console.log('[HelloWorldApplicationCustomizer._onDispose] Disposed custom top and bottom placeholders.');
    }
    

コードを SharePoint Online でテストする準備が整いました。

コードのテスト

  1. ./config/serve.json ファイルで、ファイルの [プロパティ] セクションを更新して、Top メッセージと Bottom メッセージを含めます。

    {
      "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
      "port": 4321,
      "https": true,
      "serveConfigurations": {
        "default": {
          "pageUrl": "https://sppnp.sharepoint.com/sites/mySite/SitePages/myPage.aspx",
          "customActions": {
            "54328ea6-0591-4fbd-aadb-5dc51fd53235": {
              "location": "ClientSideExtension.ApplicationCustomizer",
              "properties": {
                "Top": "Top area of the page",
                "Bottom": "Bottom area of the page"
              }
            }
          }
        },
        "helloWorld": {
          "pageUrl": "https://sppnp.sharepoint.com/sites/mySite/SitePages/myPage.aspx",
          "customActions": {
            "54328ea6-0591-4fbd-aadb-5dc51fd53235": {
              "location": "ClientSideExtension.ApplicationCustomizer",
              "properties": {
                "Top": "Top area of the page",
                "Bottom": "Bottom area of the page"
              }
            }
          }
        }
      }
    }
    

    注:

    上記の JSON の抜粋に記載されている GUID は、SPFx 拡張コンポーネントの固有 ID です。 これはコンポーネントのマニフェストで定義されます。 すべてのコンポーネント ID が一意であるため、ソリューションの GUID は異なります。

  2. gulp serve を実行しているコンソール ウィンドウに切り替えて、エラーを確認します。 Gulp はコンソールでエラーを報告します。続行する前に修正する必要があります。 ソリューションが既に実行されている場合は、それを再起動して、 serve.json ファイルから更新された設定が適用されるようにします。

    gulp serve
    
  3. [デバッグ スクリプトを読み込む] を選択して、ローカル ホストからのスクリプトの読み込みを続行します。

    ページからのデバッグ マニフェストの質問を許可する

ページにカスタムのヘッダーとフッターのコンテンツが表示されます。

ページにレンダリングされているカスタムのヘッダーおよびフッター要素

次の手順

これで完了です。アプリケーション カスタマイザーを使用してカスタムのヘッダーとフッターを構築することができました。

引き続き拡張機能を構築するには、「拡張機能を SharePoint に展開する (Hello world パート 3)」を参照してください。 デバッグ クエリ パラメーターを使用せずに、SharePoint サイト コレクションにHello World拡張機能を展開してプレビューする方法について説明します。