コアコンポーネントの拡張

既存のコアコンポーネントを拡張してAEM SPA Editor で使用する方法を説明します。 既存のコンポーネントの拡張方法を理解することは、AEM SPA Editor 実装の機能をカスタマイズおよび拡張するための強力な手法です。

目的

  1. 追加のプロパティやコンテンツを使用して、既存のコアコンポーネントを拡張します。
  2. sling:resourceSuperType を使用して、コンポーネントの継承の基本を理解します。
  3. Sling モデルの 委任パターン を活用して、既存のロジックと機能を再利用する方法を説明します。

作成する内容

この章では、新しい Card コンポーネントが作成されます。 Card コンポーネントは、 画像コアコンポーネント を拡張して、「タイトル」や「アクションの呼び出し」ボタンなどの追加のコンテンツフィールドを追加し、SPA内の他のコンテンツに対してティーザーの役割を実行します。

カードコンポーネントの最終オーサリング

メモ

実際の実装では、 ティーザーコンポーネント を使用し、 画像コアコンポーネント を拡張して Card コンポーネントをプロジェクト要件に応じて作成する方が適切な場合があります。 可能な場合は、 コアコンポーネント を直接使用することをお勧めします。

前提条件

ローカル開発環境 の設定に必要なツールと手順を確認します。

コードの取得

  1. このチュートリアルの開始点を Git からダウンロードします。

    $ git clone git@github.com:adobe/aem-guides-wknd-spa.git
    $ cd aem-guides-wknd-spa
    $ git checkout Angular/extend-component-start
    
  2. Maven を使用して、ローカルのAEMインスタンスにコードベースをデプロイします。

    $ mvn clean install -PautoInstallSinglePackage
    

    AEM 6.x を使用する場合は、classic プロファイルを追加します。

    $ mvn clean install -PautoInstallSinglePackage -Pclassic
    
  3. 従来の WKND リファレンスサイト の完成したパッケージをインストールします。 WKND 参照サイト から提供された画像は、WKND SPAで再利用されます。 パッケージは、AEM Package Manager を使用してインストールできます。

    パッケージマネージャーによる wknd.all のインストール

GitHub で完成したコードをいつでも表示できます。また、ブランチ Angular/extend-component-solution に切り替えて、コードをローカルでチェックアウトすることもできます。

Inspectの初期カード実装

チャプタースターターコードによって、初期カードコンポーネントが提供されました。 Inspectカード実装の出発点。

  1. 任意の IDE で、ui.apps モジュールを開きます。

  2. ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/card に移動し、.content.xml ファイルを表示します。

    カードコンポーネントのAEM定義の開始

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:primaryType="cq:Component"
        jcr:title="Card"
        sling:resourceSuperType="wknd-spa-angular/components/image"
        componentGroup="WKND SPA Angular - Content"/>
    

    プロパティ sling:resourceSuperTypewknd-spa-angular/components/image を指し、Card コンポーネントが WKND SPA Image コンポーネントのすべての機能を継承することを示しています。

  3. ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/image/.content.xml ファイルを検査します。

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:primaryType="cq:Component"
        jcr:title="Image"
        sling:resourceSuperType="core/wcm/components/image/v2/image"
        componentGroup="WKND SPA Angular - Content"/>
    

    sling:resourceSuperTypecore/wcm/components/image/v2/image を指していることに注意してください。 これは、WKND SPA画像コンポーネントがコアコンポーネント画像からすべての機能を継承していることを示しています。

    プロキシパターン とも呼ばれます。Sling リソースの継承は、子コンポーネントが機能を継承し、必要に応じて動作を拡張/上書きできるようにする強力なデザインパターンです。 Sling の継承は複数レベルの継承をサポートするので、最終的に、新しい Card コンポーネントはコアコンポーネント画像の機能を継承します。

    多くの開発チームは、DRY になるよう努めています(繰り返さないでください)。 Sling の継承により、AEMでこれを実現できます。

  4. card フォルダーの下で、_cq_dialog/.content.xml ファイルを開きます。

    このファイルは、Card コンポーネントのコンポーネントダイアログ定義です。 Sling の継承を使用する場合、 Sling Resource Merger の機能を使用して、ダイアログの一部を上書きまたは拡張できます。 このサンプルでは、作成者から追加データを取り込み、カードコンポーネントを設定するための新しいタブがダイアログに追加されています。

    sling:orderBefore などのプロパティを使用すると、開発者は新しいタブやフォームフィールドを挿入する場所を選択できます。 この場合、Text タブは asset タブの前に挿入されます。 Sling Resource Merger を最大限に活用するには、 画像コンポーネントのダイアログ の元のダイアログノード構造を知っておくことが重要です。

  5. card フォルダーの下で、_cq_editConfig.xml ファイルを開きます。 このファイルは、AEMオーサリング UI でのドラッグ&ドロップ動作を指示します。 画像コンポーネントを拡張する場合は、リソースタイプがコンポーネント自体に一致することが重要です。 <parameters> ノードを確認します。

    <parameters
        jcr:primaryType="nt:unstructured"
        sling:resourceType="wknd-spa-angular/components/card"
        imageCrop=""
        imageMap=""
        imageRotate=""/>
    

    ほとんどのコンポーネントには cq:editConfig は必要ありません。画像コンポーネントとその子コンポーネントは例外です。

  6. IDE スイッチで ui.frontend モジュールに移動し、ui.frontend/src/app/components/card に移動します。

    Angularコンポーネントの開始

  7. card.component.ts ファイルを検査します。

    標準の MapTo 関数を使用してAEM Card コンポーネントにマッピングするために、コンポーネントは既にスタブ化されています。

    MapTo('wknd-spa-angular/components/card')(CardComponent, CardEditConfig);
    

    srcalttitle の 3 つの @Input パラメーターを確認します。 これらは、AngularコンポーネントにマッピングされるAEMコンポーネントからの期待される JSON 値です。

  8. ファイル card.component.html を開きます。

    <div class="card"  *ngIf="hasContent">
        <app-image class="card__image" [src]="src" [alt]="alt" [title]="title"></app-image>
    </div>
    

    この例では、card.component.ts から @Input パラメーターを渡すだけで、既存のAngular画像コンポーネント app-image を再利用することを選択しました。 チュートリアルの後半で、追加のプロパティが追加され、表示されます。

テンプレートポリシーの更新

この最初の Card 実装で、AEM SPA Editor で機能を確認します。 初期の Card コンポーネントを確認するには、テンプレートポリシーを更新する必要があります。

  1. スターターコードをAEMのローカルインスタンスにデプロイします(まだデプロイしていない場合)。

    $ cd aem-guides-wknd-spa
    $ mvn clean install -PautoInstallSinglePackage
    
  2. http://localhost:4502/editor.html/conf/wknd-spa-angular/settings/wcm/templates/spa-page-template/structure.html にあるSPAページテンプレートに移動します。

  3. レイアウトコンテナのポリシーを更新して、新しい Card コンポーネントを許可されたコンポーネントとして追加します。

    レイアウトコンテナポリシーの更新

    ポリシーに対する変更を保存し、Card コンポーネントを許可されたコンポーネントとして監視します。

    許可されたコンポーネントとしてのカードコンポーネント

初期カードコンポーネントの作成

次に、AEM SPA Editor を使用して Card コンポーネントを作成します。

  1. http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html に移動します。

  2. Edit モードで、Card コンポーネントを Layout Container に追加します。

    新規コンポーネントの挿入

  3. アセットファインダーから Card コンポーネントに画像をドラッグ&ドロップします。

    画像を追加

  4. Card コンポーネントダイアログを開き、「テキスト」タブが追加されていることに注意してください。

  5. テキスト」タブで次の値を入力します。

    「テキストコンポーネント」タブ

    カードのパス - SPAホームページの下でページを選択します。

    CTA テキスト - 「詳細を表示」

    カードタイトル — 空白のまま

    リンクされたページからタイトルを取得 - true を示すチェックボックスをオンにします。

  6. 「アセットのメタデータ」タブを更新して、代替テキストキャプション の値を追加します。

    現在、ダイアログの更新後に追加の変更は表示されません。 新しいフィールドをAngularコンポーネントに公開するには、Card コンポーネントの Sling モデルを更新する必要があります。

  7. 新しいタブを開き、CRXDE-Lite に移動します。 /content/wknd-spa-angular/us/en/home/jcr:content/root/responsivegrid の下のコンテンツノードをInspectして、Card コンポーネントのコンテンツを検索します。

    CRXDE-Lite コンポーネントのプロパティ

    プロパティ cardPathctaTexttitleFromPage がダイアログで保持されることを確認します。

カード Sling モデルの更新

最終的に、コンポーネントダイアログの値をAngularコンポーネントに公開するには、Card コンポーネントの JSON を設定する Sling Model を更新する必要があります。 また、次の 2 つのビジネスロジックを実装する機会もあります。

  • titleFromPage から true の場合、cardPath で指定されたページのタイトルを返します。それ以外の場合は、cardTitle テキストフィールドの値を返します。
  • cardPath で指定されたページの最終変更日を返します。

任意の IDE に戻り、core モジュールを開きます。

  1. Card.javacore/src/main/java/com/adobe/aem/guides/wknd/spa/angular/core/models/Card.java)ファイルを開きます。

    Card インターフェイスが現在 com.adobe.cq.wcm.core.components.models.Image を拡張しているので、Image インターフェイスのすべてのメソッドを継承していることを確認します。 Image インターフェイスは既に ComponentExporter インターフェイスを拡張しているので、Sling Model を JSON 形式で書き出し、SPAエディターでマッピングできます。 したがって、 カスタムコンポーネントの章 で行ったように、ComponentExporter インターフェイスを明示的に拡張する必要はありません。

  2. インターフェイスに次のメソッドを追加します。

    @ProviderType
    public interface Card extends Image {
    
        /***
        * The URL to populate the CTA button as part of the card.
        * The link should be based on the cardPath property that points to a page.
        * @return String URL
        */
        public String getCtaLinkURL();
    
        /***
        * The text to display on the CTA button of the card.
        * @return String CTA text
        */
        public String getCtaText();
    
    
    
        /***
        * The date to be displayed as part of the card.
        * This is based on the last modified date of the page specified by the cardPath
        * @return
        */
        public Calendar getCardLastModified();
    
    
        /**
        * Return the title of the page specified by cardPath if `titleFromPage` is set to true.
        * Otherwise return the value of `cardTitle`
        * @return
        */
        public String getCardTitle();
    }
    

    これらのメソッドは、JSON モデル API を介して公開され、Angularコンポーネントに渡されます。

  3. 次を開きます: CardImpl.java. Card.java インターフェイスの実装です。 この実装は、チュートリアルを高速化するために、既に部分的にスタブ化されています。 @Model 注釈と @Exporter 注釈を使用して、Sling Model Exporter を介して Sling Model を JSON としてシリアル化できることに注意してください。

    CardImpl.java また、は Sling Model の委 任パターンを使用し て、画像コアコンポーネントのすべてのロジックが書き換えられないようにします。

  4. 次の行を確認します。

    @Self
    @Via(type = ResourceSuperType.class)
    private Image image;
    

    上記の注釈は、Card コンポーネントの sling:resourceSuperType 継承に基づいて、image という名前の画像オブジェクトをインスタンス化します。

    @Override
    public String getSrc() {
        return null != image ? image.getSrc() : null;
    }
    

    その後、image オブジェクトを使用するだけで、ロジックを自分で書く必要なく、Image インターフェイスで定義されたメソッドを実装できます。 この手法は getSrc()getAlt()getTitle() に使用されます。

  5. 次に、 initModel() メソッドを実装して、cardPath の値に基づいてプライベート変数 cardPage を開始します。

    @PostConstruct
    public void initModel() {
        if(StringUtils.isNotBlank(cardPath) && pageManager != null) {
            cardPage = pageManager.getPage(this.cardPath);
        }
    }
    

    @PostConstruct initModel() は、Sling モデルの初期化時に常に呼び出されるので、モデル内の他のメソッドで使用できるオブジェクトを初期化する良い機会です。 pageManager は、@ScriptVariable 注釈を介して Sling Model で使用可能になった、多数の Java ベースのグローバルオブジェクト の 1 つです。 getPage メソッドはパスを取得し、AEM Page オブジェクトを返します。パスが有効なページを指していない場合は null を返します。

    これにより、cardPage 変数が初期化され、他の新しいメソッドが基になるリンクされたページに関するデータを返すために使用されます。

  6. オーサーダイアログを保存した JCR プロパティに既にマッピングされているグローバル変数を確認します。 @ValueMapValue 注釈は、マッピングを自動的に実行するために使用されます。

    @ValueMapValue
    private String cardPath;
    
    @ValueMapValue
    private String ctaText;
    
    @ValueMapValue
    private boolean titleFromPage;
    
    @ValueMapValue
    private String cardTitle;
    

    これらの変数は、Card.java インターフェイスの追加のメソッドを実装するために使用されます。

  7. Card.java インターフェイスで定義された追加のメソッドを実装します。

    @Override
    public String getCtaLinkURL() {
        if(cardPage != null) {
            return cardPage.getPath() + ".html";
        }
        return null;
    }
    
    @Override
    public String getCtaText() {
        return ctaText;
    }
    
    @Override
    public Calendar getCardLastModified() {
       if(cardPage != null) {
           return cardPage.getLastModified();
       }
       return null;
    }
    
    @Override
    public String getCardTitle() {
        if(titleFromPage) {
            return cardPage != null ? cardPage.getTitle() : null;
        }
        return cardTitle;
    }
    
    メモ

    完成した CardImpl.java は、 で確認できます。

  8. ターミナルウィンドウを開き、core ディレクトリの Maven autoInstallBundle プロファイルを使用して、core モジュールの更新のみをデプロイします。

    $ cd core/
    $ mvn clean install -PautoInstallBundle
    

    AEM 6.x を使用する場合は、classic プロファイルを追加します。

  9. JSON モデルの応答を次の場所で確認します。http://localhost:4502/content/wknd-spa-angular/us/en.model.json を検索し、wknd-spa-angular/components/card を探します。

    "card": {
        "ctaText": "Read More",
        "cardTitle": "Page 1",
        "title": "Woman chillaxing with river views in Australian bushland",
        "src": "/content/wknd-spa-angular/us/en/home/_jcr_content/root/responsivegrid/card.coreimg.jpeg/1595190732886/adobestock-216674449.jpeg",
        "alt": "Female sitting on a large rock relaxing in afternoon dappled light the Australian bushland with views over the river",
        "cardLastModified": 1591360492414,
        "ctaLinkURL": "/content/wknd-spa-angular/us/en/home/page-1.html",
        ":type": "wknd-spa-angular/components/card"
    }
    

    JSON モデルは、CardImpl Sling モデルのメソッドを更新した後、追加のキーと値のペアで更新されます。

更新Angularコンポーネント

これで、JSON モデルに ctaLinkURLctaTextcardTitle および cardLastModified の新しいプロパティが入力されました。これらを表示するようにAngularコンポーネントを更新できます。

  1. IDE に戻り、ui.frontend モジュールを開きます。 必要に応じて、新しいターミナルウィンドウから webpack 開発サーバーを起動して、変更をリアルタイムで確認します。

    $ cd ui.frontend
    $ npm install
    $ npm start
    
  2. ui.frontend/src/app/components/card/card.component.tscard.component.ts を開きます。 追加の @Input 注釈を追加して、新しいモデルをキャプチャします。

    export class CardComponent implements OnInit {
    
         @Input() src: string;
         @Input() alt: string;
         @Input() title: string;
    +    @Input() cardTitle: string;
    +    @Input() cardLastModified: number;
    +    @Input() ctaLinkURL: string;
    +    @Input() ctaText: string;
    
  3. コールトゥアクションの準備ができたかどうかを確認し、cardLastModified 入力に基づいて日付/時間文字列を返すためのメソッドを追加します。

    export class CardComponent implements OnInit {
        ...
        get hasCTA(): boolean {
            return this.ctaLinkURL && this.ctaLinkURL.trim().length > 0 && this.ctaText && this.ctaText.trim().length > 0;
        }
    
        get lastModifiedDate(): string {
            const lastModifiedDate = this.cardLastModified ? new Date(this.cardLastModified) : null;
    
            if (lastModifiedDate) {
            return lastModifiedDate.toLocaleDateString();
            }
            return null;
        }
        ...
    }
    
  4. card.component.html を開き、次のマークアップを追加して、タイトル、行動喚起、最終変更日を表示します。

    <div class="card"  *ngIf="hasContent">
        <app-image class="card__image" [src]="src" [alt]="alt" [title]="title"></app-image>
        <div class="card__content">
            <h2 class="card__title">
                {{cardTitle}}
                <span class="card__lastmod" *ngIf="lastModifiedDate">{{lastModifiedDate}}</span>
            </h2>
            <div class="card__action-container" *ngIf="hasCTA">
                <a [routerLink]="ctaLinkURL" class="card__action-link" [title]="ctaText">
                    {{ctaText}}
                </a>
            </div>
        </div>
    </div>
    

    card.component.scss に、タイトルのスタイル設定、行動喚起、最終変更日の設定を行うための Sass ルールが既に追加されています。

    メモ
  5. Maven を使用して、プロジェクトのルートからAEMに完全な変更をデプロイします。

    $ cd aem-guides-wknd-spa
    $ mvn clean install -PautoInstallSinglePackage
    
  6. http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html に移動して、更新されたコンポーネントを確認します。

    AEMのカードコンポーネントの更新

  7. 既存のコンテンツを再オーサリングして、次のようなページを作成できるはずです。

    カードコンポーネントの最終オーサリング

おめでとうございます。

これで、を使用してAEMコンポーネントを拡張する方法と、Sling のモデルとダイアログが JSON モデルと連携する方法を学びました。

GitHub で完成したコードをいつでも表示できます。また、ブランチ Angular/extend-component-solution に切り替えて、コードをローカルでチェックアウトすることもできます。

このページ