JSS Angular アプリでのプレースホルダーの操作

Version: 20.x
日本語翻訳に関する免責事項

このページの翻訳はAIによって自動的に行われました。可能な限り正確な翻訳を心掛けていますが、原文と異なる表現や解釈が含まれる場合があります。正確で公式な情報については、必ず英語の原文をご参照ください。

プレースホルダーは、Sitecore JSS で構築されたすべてのアプリケーションに欠かせないコンポーネントです。このトピックでは、Sitecore JSS Angular サンプル アプリケーションを使用して、その例を示します。

JSS Angular サンプル アプリケーションには、ルート プレースホルダーが付属しています。ルート プレースホルダーは src/app/routing/layout/layout.component.html で定義されています。

sc-placeholder コンポーネントが Angular 用 Sitecore JSS (@sitecorelabs/sitecore-jss-angular) からインポートされます。

RequestResponse
<sc-placeholder name="jss-main" [rendering]="route" (loaded)="onPlaceholderLoaded($event)"></sc-placeholder><sc-placeholder name="jss-main" [rendering]="route"></sc-placeholder>

sc-placeholderAngular コンポーネントは、jss-main という値の name 属性を保持しています。この属性は jss-main という名前の Sitecore プレースホルダーを表しています。プレースホルダーは、プレースホルダー コンポーネントの [rendering] 入力にバインドされたデータで示されるように、ルート データに基づいて 1 つ以上のコンポーネントをレンダリングします。

RequestResponse
<sc-placeholder name="jss-main" [rendering]="route" (loaded)="onPlaceholderLoaded($event)"></sc-placeholder>
注記

sc-placeholder を、既存の DOM 要素に属性として適用できます。

ルート データの発生元の理解

プレースホルダー コンポーネントが route データを受け取る方法を理解するには、さまざまなコンポーネント、アプリケーション モジュール、サービスがどのように相互連携するかを理解する必要があります。

本番環境では、ユニバーサル レンダリングをサポートするために、JSS Angular アプリケーションを構築するためのスクリプトによって、サーバー バンドルとクライアント バンドルが構築されます。スクリプト jss build を実行すると、これらのバンドルは以下の場所に配置されます。

  • クライアント バンドル - dist/browser/

  • サーバー バンドル - dist/server.bundle.js

2 つのバンドルは単独では実行できません。これらのバンドルはサービスされる必要があり、そのためにはサーバーが必要になります。JSS には、サーバー バンドルを実行できる Node 用の JavaScript ビュー エンジンが付属しています。JSS JavaScript ビュー エンジンでは、renderView 関数をエクスポートするサーバー バンドルが必要になります。

2 つのバンドルを構築し、サービスするために、JSS Angular アプリでは、関連するアプリ モジュールとデータ サービスに基づいて、アプリケーション用の 2 つのエントリ ポイントを定義します。

ファイル src/main.server.ts では、サーバー バンドルのエントリ ポイントが定義され、src/app/app.server.module.ts で定義されているサーバー AppServerModule 用のアプリケーション モジュールがブートストラップされます。AppServerModule は、src/app/jss-context.server-side.service.ts で定義されている JssContextServerSideService (サーバー上で実行され、JSS アプリのコンテキスト データを格納) を使用します。コンテキスト データには、現在のルートのデータと Sitecore コンテキスト データが含まれています。

ファイル src/main.ts では、クライアント バンドルのエントリ ポイントが定義され、src/app/app.module.ts で定義されているクライアント レンダリング AppModule用のアプリケーション モジュールがブートストラップされます。AppModule は、src/app/jss-context.service.ts で定義されている JssContextService (クライアント上でブラウザーを使って実行され、JSS アプリのコンテキスト データを格納) を使用します。

アプリケーションがブラウザで実行されると、サーバーはサーバー バンドルから、AppServerModule をレンダリングする renderView 関数を呼び出し、JSS アプリ用のコンテキスト データを準備します。実装の詳細については、ファイル server.bundle.ts および関連するサービスを参照してください。どちらのコンテキスト サービスも Angular のクラス TransferState を使用しています。このクラスは、データを正規化した後でサーバー側のアプリケーション モジュールからクライアント側のアプリケーション モジュールに転送されるキー値ストアです。

RequestResponse
    renderModule(AppServerModule, {
      document: template,
      url: path,
      extraProviders: [
        // custom injection with the initial state that SSR should utilize
        { provide: 'JSS_SERVER_LAYOUT_DATA', useValue: transferState },
        { provide: 'JSS_SERVER_VIEWBAG', useValue: state.viewBag },
      ],
    })
      .then((html) => callback(null, { html }))
      .catch((err) => callback(err, null));

クライアント側の AppModule は、src/app/app.component.ts で定義されたルート アプリケーション コンポーネント AppComponent をブートストラップし、ファイル src/app/routing/routing.module.ts で定義された RoutingModule クラスをインポートします。RoutingModule は、Angular ルーターをアプリケーション ルートにアタッチする処理を実行します。これにより、JSS Angular アプリでは Angular ルーター アウトレットを使用することが可能になります。

RoutingModule は、ルーター アウトレット プレースホルダーでレンダリングするコンポーネントを定義します。このコンポーネントは、src/app/routing/layout/layout.component.ts ファイルで定義されている LayoutComponent です。RoutingModule は、ルートを解決するときにアクティブなルートの状態を設定する JssRouteResolver プロバイダーを使用します。

最後に、route とレイアウト データの両方が挿入された LayoutComponent では、アクティブなルートをサブスクライブし、Sitecore コンテキストからルート データを抽出することができます。

この時点で、プレースホルダー コンポーネントは、本番環境の設定においてルートの HTML マークアップをレンダリングすることができます。

切断モードで作業している場合、JSS アプリケーションはローカルに定義されたファイルからルート データを取得します。サンプル アプリケーションでは、事前定義されたローカル データがフォルダ src/data に保存されています。ホーム ページなどのルートを読み込むとき、アプリケーションはファイル src/data/en.yml からデータを取得します。応答には、ルートの JSON データが含まれています。

RequestResponse
{
  "context": {
    "pageEditing": false,
    "site": {
      "name": "JssDisconnectedLayoutService"
    },
    "pageState": "normal",
    "language": "en"
  },
  "route": {
    "databaseName": "available-in-connected-mode",
    "deviceId": "available-in-connected-mode",
    "itemId": "home-page",
    "itemLanguage": "en",
    "itemVersion": 1,
    "layoutId": "available-in-connected-mode",
    "templateId": "available-in-connected-mode",
    "templateName": "available-in-connected-mode",
    "name": "home",
    "fields": {
      "pageTitle": {
        "value": "Welcome to Sitecore JSS"
      }
    },
    "placeholders": {
      "jss-main": [
        {
          "uid": "{2C4A53CC-9DA8-5F51-9D79-6EE2FC671B2D}",
          "componentName": "ContentBlock",
          "dataSource": "available-in-connected-mode",
          "params": {},
          "fields": {
            "heading": {
              "value": "Welcome to Sitecore JSS"
            },
            "content": {
              "value": "<p>Thanks for using JSS. Here are some resources to get you started:</p>"
            }
          }
        }
      ]
    }
  }}

route プロパティの JSON データ構造には、placeholders のリストが含まれています。各プレースホルダーの名前は、コンポーネントの配列に関連付けられています。プレースホルダーへのコンポーネントのマッピングは、コンポーネント配置ルールと呼ばれます。

sc-placeholder コンポーネントは route プロパティ内の placeholders オブジェクトにアクセスできるため、このコンポーネントでは、名前 (jss-main) を使用して一致するプレースホルダーを検索し、プレースホルダー内のコンポーネントの配列をレンダリングします。この例では、一般的な Angular コンポーネントである ContentBlockComponent コンポーネントを動的にレンダリングし、依存関係挿入トークンを介して headingcontent というフィールドを提供します。

RequestResponse
import { Component, Input } from '@angular/core';
import { ComponentRendering } from '@sitecore-jss/sitecore-jss-angular';
@Component({
  selector: 'app-content-block',
  templateUrl: './content-block.component.html',
})
export class ContentBlockComponent {
  @Input() rendering: ComponentRendering;
}

rendering プロパティには、データから取得される ContentBlockComponent コンポーネントに関連するすべての情報が含まれています。

RequestResponse
"componentName": "ContentBlock",
    "dataSource": "available-in-connected-mode",
    "params": {},
    "fields": {
        "heading": {
            "value": "Welcome to Sitecore JSS"
        },
    "content": {
        "value": "<p>Thanks for using JSS. Here are some resources to get you started:</p>"
    }
}

プレースホルダーとコンポーネントのネスト

コンポーネントには独自の sc-placeholder コンポーネントを含めることができるため、コンポーネントの配置ルールで placeholders を使用して、このコンポーネントの内容を定義できます。

たとえば、WelcomeComponent コンポーネントには、次が含まれる場合があります。

RequestResponse
@Component({
  selector: 'app-welcome',
  template: `
    <sc-placeholder name="welcome" [rendering]="rendering"></sc-placeholder>
  `
})
export class WelcomeComponent {
  rendering: any;
}

この場合、コンポーネント配置ルールで子コンポーネントを定義します。

RequestResponse
{
  componentName: 'Welcome',
    fields: {
      title: {
        value: 'Sitecore Experience Platform + JSS',
      },
      text: {
        value: '<p>...</p>',
      },
      logoImage: {
        value: {
          src: '/assets/img/sc_logo.png',
          alt: 'Logo'
        },
      },
    },
    placeholders: {
      welcome: [
        {
          componentName: 'AnotherComponent',
          fields: {
            /* etc */
          }
        }
      ]
    }
}

入力バインディングと出力バインディング

sc-placeholder[inputs][outputs] のバインディング プロパティを使用して、カスタム プロパティをコンポーネントにバインドできます。これらのプロパティにより、プレースホルダー内にあるすべてのコンポーネントのプロパティに対する入出力バインディングが可能になります。

このため、子コンポーネントが sc-placeholder によって動的に作成された場合でも、子コンポーネントとのオーケストレーション/インタラクション を行うことができます。これは、Sitecore XP でも管理/最適化を行う必要がある複雑なユーザー フローで特に役立ちます。

[inputs][outputs] の簡単な使用例を次に示します。

RequestResponse
@Component({
  selector: 'my-container-component',
  template: `<sc-placeholder
                name="placeholder"
                [rendering]="rendering"
                [inputs]="inputs"
                [outputs]="outputs"
                ></sc-placeholder>`
})
class MyContainerComponent {
  @Input() public rendering: any;

  inputs = {
    hello: 'world',
    something: () => 'can be really complex'
  };
  outputs = {
    onSomething: (type) => alert(type)
  }
}

@Component({selector: 'my-rendering')
class MyRendering {
  // standard on any placeholder-managed component
  @Input() public rendering: any;

  // additional properties for input/output binding
  @Input() hello: string;
  @Input() something: Function;
  @Output() onSomething = new EventEmitter<string>();
}

プレースホルダーの遅延読み込み

Sitecore コンポーネントを遅延読み込みすると、既定ではプレースホルダーが空で表示されます。コンポーネントの読み込み中に表示されるコンポーネントの一時的な本体を指定できます。コンポーネントの読み込みが完了すると、一時的な本体が実際のコンテンツに置き換わります。簡単な例を次に示します。

RequestResponse
  <sc-placeholder [rendering]="rendering">
    <img *scPlaceholderLoading src="loading.gif">
  </sc-placeholder>

プレースホルダーの強化

Placeholder コンポーネントは、開発者エクスペリエンスを向上させるいくつかのカスタマイズをサポートしています。

エラー コンポーネント

プレースホルダーでレンダリング エラーが発生した場合、プレースホルダーにはプレースホルダーのコンテンツではなくエラー コンポーネントが表示され、エラーの詳細がコンソールに記録されます。このコンポーネントをカスタマイズするには、errorComponent プロップを使って、独自の React コンポーネントを代わりに使用します。

MissingComponent コンポーネント

componentFactory で認識されないレンダリング名がプレースホルダーに含まれている場合 (たとえば、バックエンド開発者が Foo レンダリングを作成し、それをページに追加したが、foo.component.ts がまだ存在していない場合)、レンダリングは、Angular コンポーネントの missingComponentComponent プロパティで定義された MissingComponent コンポーネントに置き換えられます。既定の実装はシンプルなメッセージですが、missingComponentComponent プロパティで独自の Angular コンポーネントを使用して、この実装をカスタマイズできます。

非表示のレンダリングの処理

レンダリングがパーソナライゼーション ルールによって非表示になっている場合、レンダリングに JSS 実装が欠落している際のエラー メッセージを回避するために、レンダリングは HiddenRendering コンポーネントに置き換えられます。hiddenRenderingComponent プロパティを使用することで、独自のコンポーネントを作成し、プレースホルダーに提供できます。

何かフィードバックはありますか?

この記事を改善するための提案がある場合は、