AEM SPA Editorを使用した開発 — Hello Worldチュートリアル

警告

このチュートリアルは​非推奨​です。 次のいずれかを実行することをお勧めします。AEM SPA EditorおよびAngularの概要またはAEM SPA EditorおよびReactの概要

AEM SPA Editorは、シングルページアプリケーションまたはSPAのコンテキスト内編集をサポートします。 このチュートリアルでは、AEM SPA Editor JS SDKで使用するSPA開発の概要を説明します。 このチュートリアルでは、カスタムHello Worldコンポーネントを追加して、We.Retailジャーナルアプリを拡張します。 ユーザーは、ReactフレームワークまたはAngularフレームワークを使用して、チュートリアルを完了できます。

メモ

シングルページアプリケーション(SPA)エディター機能には、AEM 6.4サービスパック2以降が必要です。

SPA Editorは、SPAフレームワークベースのクライアントサイドレンダリング(ReactやAngularなど)が必要なプロジェクトで推奨されるソリューションです。

前提条件の読み取り

このチュートリアルでは、コンテキスト内編集を有効にするために、SPAコンポーネントをAEMコンポーネントにマッピングするために必要な手順を説明します。 このチュートリアルを開始するユーザーは、Adobe Experience Manager、AEMの開発の基本概念と、AngularフレームワークのReactを使用した開発に精通している必要があります。 このチュートリアルでは、バックエンドとフロントエンドの両方の開発タスクについて説明します。

このチュートリアルを開始する前に、次のリソースを確認することをお勧めします。

ローカル開発環境

このチュートリアルは、次の用途に設計されています。

Adobe Experience Manager 6.5 または Adobe Experience Manager 6.4 + Service Pack 5

このチュートリアルでは、次のテクノロジーとツールをインストールする必要があります。

  1. Java 11
  2. Apache Maven - 3.3.1以降
  3. Node.js - 8.11.1以降お よびnpm 5.6.0以降(npmはnode.jsと共にインストールされます)

新しいターミナルを開き、次のコマンドを実行して、上記のツールのインストールを再確認します。

$ java -version
java version "11 +"

$ mvn -version
Apache Maven 3.3.9

$ node --version
v8.11.1

$ npm --version
6.1.0

概要

基本的な概念は、SPAコンポーネントをAEMコンポーネントにマッピングすることです。 AEMコンポーネントは、サーバー側で実行され、JSON形式でコンテンツを書き出します。 JSONコンテンツは、ブラウザーでクライアント側を実行するSPAで使用されます。 SPAコンポーネントとAEMコンポーネントの間に1対1のマッピングが作成されます。

SPAコンポーネントのマッピング

一般的なフレームワークReact JSAngularは、すぐに使用できます。 ユーザーは、最も慣れたAngularまたはReactのいずれでも、このチュートリアルを完了できます。

プロジェクトのセットアップ

SPAの開発はAEMの開発で1フィート、もう1フィートです。 目標は、SPAの開発を独立して(ほとんどが)AEMに依存しないようにすることです。

  • SPAプロジェクトは、フロントエンド開発時に、AEMプロジェクトとは独立して動作します。
  • Webpack、NPM、Grunt、Gulpなどのフロントエンドビルドツールとテクノロジーは、引き続き使用されます。
  • AEM用にビルドするには、SPAプロジェクトがコンパイルされ、AEMプロジェクトに自動的に含まれます。
  • SPAをAEMにデプロイする際に使用する標準AEMパッケージです。

アーティファクトとデプロイメントの概要

SPAの開発にはAEMの開発が1つあり、もう1つはSPAの開発が独立しておこなわれ、(ほとんどが)AEMに依存しないことが可能です。

このチュートリアルの目標は、 We.Retailジャーナルアプリを新しいコンポーネントで拡張することです。 まず、We.Retail Journalアプリのソースコードをダウンロードし、ローカルAEMにデプロイします。

  1. ​最新の We.RetailジャーナルコードをGitHubからダウンロードします

    または、コマンドラインからリポジトリのクローンを作成します。

    $ git clone git@github.com:adobe/aem-sample-we-retail-journal.git
    
    メモ

    このチュートリアルは、1.2.1-SNAPSHOT​バージョンのプロジェクトで、master​ブランチに対して動作します。

  2. 次の構造が表示されます。

    プロジェクトフォルダー構造

    プロジェクトには、次のMavenモジュールが含まれています。

    • all:プロジェクト全体を1つのパッケージに埋め込んでインストールします。
    • bundles:次の2つのOSGiバンドルが含まれます。とその他のJavaコードを含 Sling Models むコモンとコア。
    • ui.apps:には、プロジェクトの/apps部分(JSおよびCSS clientlib、コンポーネント、実行モード固有の設定)が含まれます。
    • ui.content:構造コンテンツと設定(/content/conf)を含む
    • react-app:We.RetailジャーナルReactアプリケーション。これは、MavenモジュールとWebpackプロジェクトの両方です。
    • angular-app:We.RetailジャーナルAngularアプリケーション。これはMavenモジュールとwebpackプロジェクトの両方です。
  3. 新しいターミナルウィンドウを開き、次のコマンドを実行して、http://localhost:4502上で実行されているローカルAEMインスタンスにアプリ全体をビルドしてデプロイします。

    $ cd <src>/aem-sample-we-retail-journal
    $ mvn -PautoInstallSinglePackage clean install
    
    メモ

    このプロジェクトでは、プロジェクト全体をビルドおよびパッケージ化するMavenプロファイルはautoInstallSinglePackageです。

    注意

    ビルド中にエラーが発生した場合は、Maven settings.xmlファイルにAdobeのMavenアーティファクトリポジトリが含まれていることを確認します。

  4. 次の URL に移動します。

    We.RetailジャーナルアプリがAEM Sitesエディター内に表示されます。

  5. 編集モードで、編集するコンポーネントを選択し、コンテンツを更新します。

    コンポーネントの編集

  6. ページのプロパティアイコンを選択して、ページのプロパティを開きます。 「テンプレートを編集」を選択して、ページのテンプレートを開きます。

    ページプロパティメニュー

  7. SPAエディターの最新バージョンでは、従来のSites実装と同じ方法で編集可能なテンプレートを使用できます。 これは、後でカスタムコンポーネントで再度表示されます。

    メモ

    編集可能なテンプレートは、AEM 6.5とAEM 6.4 + Service Pack 5​でのみサポートされます。

開発の概要

開発の概要

SPAの開発の繰り返しは、AEMとは独立しておこなわれます。 SPAをAEMにデプロイする準備が整ったら、(上の図に示すように)次の大まかな手順を実行します。

  1. AEMプロジェクトビルドが呼び出され、SPAプロジェクトのビルドがトリガーされます。 We.Retailジャーナルは、frontend-maven-pluginを使用します。
  2. SPAプロジェクトの​aem-clientlib-generatorは、コンパイル済みのSPAをAEMプロジェクトにAEMクライアントライブラリとして埋め込みます。
  3. AEMプロジェクトは、コンパイル済みのSPAと、その他のサポートするAEMコードを含むAEMパッケージを生成します。

AEMコンポーネントの作成

担当者:AEM 開発者

最初にAEMコンポーネントが作成されます。 AEMコンポーネントは、Reactコンポーネントによって読み取られるJSONプロパティのレンダリングを担当します。 AEMコンポーネントは、コンポーネントの編集可能なプロパティのダイアログを提供する役割も果たします。

Eclipseまたは他のIDEを使用して、We.Retail Journal Mavenプロジェクトをインポートします。

  1. リアクター​pom.xml​を更新して、Apache Ratプラグインを削除します。 このプラグインは、各ファイルをチェックして、Licenseヘッダーがあることを確認します。 この機能に関心を持つ必要はありません。

    aem-sample-we-retail-journal/pom.xml​で、apache-rate-plugin​を削除します。

    <!-- Remove apache-rat-plugin -->
    <plugin>
            <groupId>org.apache.rat</groupId>
            <artifactId>apache-rat-plugin</artifactId>
            <configuration>
                <excludes combine.children="append">
                    <exclude>*</exclude>
                        ...
                </excludes>
            </configuration>
            <executions>
                    <execution>
                        <phase>verify</phase>
                        <goals>
                            <goal>check</goal>
                        </goals>
                </execution>
            </executions>
        </plugin>
    
  2. we-retail-journal-content (<src>/aem-sample-we-retail-journal/ui.apps)モジュールで、ui.apps/jcr_root/apps/we-retail-journal/componentsの下に​cq:Component​型の​helloworld​という名前の新しいノードを作成します。

  3. helloworld​コンポーネントに次のプロパティを追加します。以下に示すXML(/helloworld/.content.xml)で表されます。

    <?xml version="1.0" encoding="UTF-8"?>
    <jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
        jcr:description="Hello World Component for We.Retail Journal"
        jcr:primaryType="cq:Component"
        jcr:title="Hello World"
        componentGroup="We.Retail Journal" />
    

    Hello Worldコンポーネント

    メモ

    編集可能テンプレート機能を説明するために、意図的にcomponentGroup="Custom Components"を設定しました。 実際のプロジェクトでは、コンポーネントグループの数を最小限に抑えることをお勧めします。そのため、他のコンテンツコンポーネントに合わせて「We.Retail Journal」を適切なグループにします。

    AEM 6.5とAEM 6.4 + Service Pack 5​のみが編集可能なテンプレートをサポートしています。

  4. 次に、Hello World​コンポーネント用にカスタムメッセージを設定するためのダイアログが作成されます。 /apps/we-retail-journal/components/helloworldの下に、nt:unstructured​のノード名​cq:dialog​を追加します。

  5. cq:dialog​には、message​という名前のプロパティに対するテキストを保持する1つのテキストフィールドが表示されます。 新しく作成した​cq:dialog​の下に、以下のノードとプロパティを追加します。これらのノードとプロパティは、以下のXML(helloworld/_cq_dialog/.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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
        jcr:primaryType="nt:unstructured"
        jcr:title="We.Retail Journal - Hello World"
        sling:resourceType="cq/gui/components/authoring/dialog">
        <content
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/container">
            <items jcr:primaryType="nt:unstructured">
                <tabs
                    jcr:primaryType="nt:unstructured"
                    sling:resourceType="granite/ui/components/coral/foundation/tabs"
                    maximized="{Boolean}true">
                    <items jcr:primaryType="nt:unstructured">
                        <properties
                            jcr:primaryType="nt:unstructured"
                            jcr:title="Properties"
                            sling:resourceType="granite/ui/components/coral/foundation/container"
                            margin="{Boolean}true">
                            <items jcr:primaryType="nt:unstructured">
                                <columns
                                    jcr:primaryType="nt:unstructured"
                                    sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
                                    margin="{Boolean}true">
                                    <items jcr:primaryType="nt:unstructured">
                                        <column
                                            jcr:primaryType="nt:unstructured"
                                            sling:resourceType="granite/ui/components/coral/foundation/container">
                                            <items jcr:primaryType="nt:unstructured">
                                                <message
                                                    jcr:primaryType="nt:unstructured"
                                                    sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
                                                    fieldLabel="Message"
                                                    name="./message"
                                                    required="{Boolean}true"/>
                                            </items>
                                        </column>
                                    </items>
                                </columns>
                            </items>
                        </properties>
                    </items>
                </tabs>
            </items>
        </content>
    </jcr:root>
    

    ファイル構造

    上記のXMLノード定義は、ユーザーが「メッセージ」を入力できる単一のテキストフィールドを持つダイアログを作成します。 <message />ノード内のプロパティname="./message"に注意してください。 これは、AEM内のJCRに保存されるプロパティの名前です。

  6. 次に、空のポリシーダイアログが作成されます(cq:design_dialog)。 テンプレートエディターでコンポーネントを表示するには、ポリシーダイアログが必要です。 このシンプルな使用例では、空のダイアログになります。

    /apps/we-retail-journal/components/helloworldの下に、nt:unstructuredのノード名cq:design_dialogを追加します。

    設定は、以下のXMLで表されます(helloworld/_cq_design_dialog/.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" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
    jcr:primaryType="nt:unstructured" />
    
  7. コマンドラインからAEMにコードベースをデプロイします。

    $ cd <src>/aem-sample-we-retail-journal/content
    $ mvn -PautoInstallPackage clean install
    

    CRXDE Liteで、/apps/we-retail-journal/components:の下のフォルダーを調べて、コンポーネントがデプロイされたことを検証します。

    デプロイ済みのコンポーネント構造のCRXDE Lite

Slingモデルの作成

担当者:AEM 開発者

次に、Sling ModelコンポーネントをバックするHello Worldが作成されます。 従来のWCMの使用例では、 Sling Modelがビジネスロジックを実装し、サーバー側レンダリングスクリプト(HTL)がSling Modelを呼び出します。 これにより、レンダリングスクリプトが比較的シンプルになります。

Sling Models は、サーバー側のビジネスロジックを実装するSPAの使用例でも使用されます。違いは、SPAの使用例では、Sling Modelsがそのメソッドをシリアル化されたJSONとして公開する点です。

メモ

ベストプラクティスとして、開発者は可能な限りAEMコアコンポーネントを使用するようにしてください。 他の機能の中でも、コアコンポーネントは「SPA対応」のJSON出力をSling Modelsに提供し、開発者はフロントエンドプレゼンテーションに専念できます。

  1. 任意のエディターで、we-retail-journal-commons​プロジェクト(<src>/aem-sample-we-retail-journal/bundles/commons)を開きます。

  2. パッケージcom.adobe.cq.sample.spa.commons.impl.models内:

    • HelloWorldという名前の新しいクラスを作成します。
    • com.adobe.cq.export.json.ComponentExporter.の実装インターフェイスを追加します。

    新しいJavaクラスウィザード

    ComponentExporterインターフェイスは、Sling ModelがAEM Content Servicesと互換性を持つように実装する必要があります。

     package com.adobe.cq.sample.spa.commons.impl.models;
    
     import com.adobe.cq.export.json.ComponentExporter;
    
     public class HelloWorld implements ComponentExporter {
    
         @Override
         public String getExportedType() {
             return null;
         }
     }
    
  3. RESOURCE_TYPEという名前の静的変数を追加して、HelloWorldコンポーネントのリソースタイプを識別します。

     ...
     public class HelloWorld implements ComponentExporter {
    
         static final String RESOURCE_TYPE = "we-retail-journal/components/helloworld";
    
         ...
     }
    
  4. @Model@ExporterのOSGi注釈を追加します。 @Model注釈は、クラスをSling Modelとして登録します。 @Exporter注釈は、Jackson Exporterフレームワークを使用して、メソッドをシリアル化されたJSONとして公開します。

    import org.apache.sling.api.SlingHttpServletRequest;
    import org.apache.sling.models.annotations.Exporter;
    import org.apache.sling.models.annotations.Model;
    import com.adobe.cq.export.json.ExporterConstants;
    ...
    
    @Model(
            adaptables = SlingHttpServletRequest.class,
            adapters = {ComponentExporter.class},
            resourceType = HelloWorld.RESOURCE_TYPE
    )
    @Exporter(
            name = ExporterConstants.SLING_MODEL_EXPORTER_NAME, 
            extensions = ExporterConstants.SLING_MODEL_EXTENSION
    )
    public class HelloWorld implements ComponentExporter {
    
    ...
    
  5. メソッドgetDisplayMessage()を実装して、JCRプロパティmessageを返します。 @ValueMapValueのSling Model注釈を使用すると、コンポーネントの下に保存されているプロパティmessageを簡単に取得できます。 @Optional注釈は重要です。コンポーネントが最初にページに追加されると、messageに値が入力されなくなるからです。

    ビジネスロジックの一部として、文字列「Hello」がメッセージの先頭に追加されます。

    import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
    import org.apache.sling.models.annotations.Optional;
    
    ...
    
    public class HelloWorld implements ComponentExporter {
    
       static final String RESOURCE_TYPE = "we-retail-journal/components/helloworld";
    
       private static final String PREPEND_MSG = "Hello";
    
        @ValueMapValue @Optional
        private String message;
    
        public String getDisplayMessage() {
            if(message != null && message.length() > 0) {
                return PREPEND_MSG + " "  + message;
            }
            return null;
        }
    
    ...
    
    メモ

    メソッド名getDisplayMessageは重要です。 Sling ModelがJackson Exporterでシリアル化されると、JSONプロパティとして公開されます。displayMessage. Jackson Exporterは、(無視するように明示的にマークされていない限り)パラメーターを受け取らないすべてのgetterメソッドをシリアル化して公開します。 後でReact /Angularアプリで、このプロパティ値を読み取り、アプリの一部として表示します。

    メソッドgetExportedTypeも重要です。 コンポーネントresourceTypeの値を使用して、JSONデータをフロントエンドコンポーネント(Angular/React)に「マッピング」します。 次の節でこれについて説明します。

  6. メソッドgetExportedType()を実装して、HelloWorldコンポーネントのリソースタイプを返します。

     @Override
        public String getExportedType() {
            return RESOURCE_TYPE;
        }
    

    HelloWorld.java​の完全なコードは、こちらを参照してください。

  7. Apache Mavenを使用してAEMにコードをデプロイします。

    $ cd <src>/sample-we-retail-spa-content/bundles/commons
    $ mvn -PautoInstallPackage clean install
    

    OSGiコンソールでStatus / Sling Modelsに移動して、Sling Modelのデプロイメントと登録を確認します。

    HelloWorld Sling Modelがwe-retail-journal/components/helloworld Slingリソースタイプにバインドされ、Sling Model Exporter Servletとして登録されていることがわかります。

    com.adobe.cq.sample.spa.commons.impl.models.HelloWorld - we-retail-journal/components/helloworld
    com.adobe.cq.sample.spa.commons.impl.models.HelloWorld exports 'we-retail-journal/components/helloworld' with selector 'model' and extension '[Ljava.lang.String;@6480f3e5' with exporter 'jackson'
    

Reactコンポーネントの作成

担当者:フロントエンド開発者

次に、Reactコンポーネントが作成されます。 react-app​モジュール(<src>/aem-sample-we-retail-journal/react-app)を、任意のエディターで開きます。

メモ

Angular開発のみをご利用の場合は、このセクションを省略してください。

  1. react-appフォルダー内で、srcフォルダーに移動します。 componentsフォルダーを展開して、既存のReactコンポーネントファイルを表示します。

    Reactコンポーネントのファイル構造

  2. componentsフォルダーの下にHelloWorld.jsという名前の新しいファイルを追加します。

  3. HelloWorld.js を開きます。Reactコンポーネントライブラリを読み込むためのimport文を追加します。 2つ目のimport文を追加して、Adobeが提供するMapToヘルパーをインポートします。 MapToヘルパーは、ReactコンポーネントのAEMコンポーネントのJSONへのマッピングを提供します。

    import React, {Component} from 'react';
    import {MapTo} from '@adobe/cq-react-editable-components';
    
  4. インポートの下に、React Componentインターフェイスを拡張するHelloWorldという新しいクラスを作成します。 必要なrender()メソッドをHelloWorldクラスに追加します。

    import React, {Component} from 'react';
    import {MapTo} from '@adobe/cq-react-editable-components';
    
    class HelloWorld extends Component {
    
        render() {
    
        }
    }
    
  5. MapToヘルパーには、Reactコンポーネントのpropの一部としてcqModelという名前のオブジェクトが自動的に含まれます。 cqModelには、Sling Modelによって公開されるすべてのプロパティが含まれます。

    前に作成したSling Modelには、メソッドgetDisplayMessage()が含まれています。 getDisplayMessage() は、出力時にという名前のJSONキーとし displayMessage て変換されます。

    render()メソッドを実装して、displayMessageの値を含むh1タグを出力します。 JSX(JavaScriptの構文拡張)は、コンポーネントの最終的なマークアップを返すために使用されます。

    ...
    
    class HelloWorld extends Component {
        render() {
    
            if(this.props.displayMessage) {
                return (
                    <div className="cmp-helloworld">
                        <h1 className="cmp-helloworld_message">{this.props.displayMessage}</h1>
                    </div>
                );
            }
            return null;
        }
    }
    
  6. 設定編集メソッドを実装します。 このメソッドはMapToヘルパーを介して渡され、コンポーネントが空の場合にプレースホルダーを表示する情報をAEMエディターに提供します。 これは、コンポーネントがSPAに追加されたが、まだオーサリングされていない場合に発生します。 HelloWorldクラスの下に次を追加します。

    ...
    
    class HelloWorld extends Component {
        ...
    }
    
    const HelloWorldEditConfig = {
    
        emptyLabel: 'Hello World',
    
        isEmpty: function(props) {
            return !props || !props.displayMessage || props.displayMessage.trim().length < 1;
        }
    };
    
    ...
    
  7. ファイルの最後で、 MapToヘルパーを呼び出し、 HelloWorldクラスとHelloWorldEditConfigを渡します。 これにより、AEMコンポーネントのリソースタイプに基づいて、ReactコンポーネントがAEMコンポーネントにマッピングされます。we-retail-journal/components/helloworld.

    MapTo('we-retail-journal/components/helloworld')(HelloWorld, HelloWorldEditConfig);
    

    HelloWorld.js​の完成したコードは、こちらを参照してください。

  8. ImportComponents.js ファイルを開きます。<src>/aem-sample-we-retail-journal/react-app/src/ImportComponents.jsにあります。

    コンパイル済みJavaScriptバンドル内の他のコンポーネントとHelloWorld.jsを必要とする行を追加します。

    ...
      require('./components/Text');
      require('./components/Image');
      require('./components/HelloWorld');
    ...
    
  9. componentsフォルダーに、HelloWorld.cssという名前の新しいファイルをHelloWorld.js.の兄弟として作成します。次のようにファイルを設定して、HelloWorldコンポーネントの基本的なスタイルを作成します。

    /* HelloWorld.css to style HelloWorld component */
    
    .cmp-helloworld_message {
        text-align: center;
        color: #ff505e;
        text-transform: unset;
        letter-spacing: unset;
    }
    
  10. HelloWorld.jsを再度開き、HelloWorld.cssが必要になるようにimport文の下で更新します。

    import React, {Component} from 'react';
    import {MapTo} from '@adobe/cq-react-editable-components';
    
    require('./HelloWorld.css');
    
    ...
    
  11. Apache Mavenを使用してAEMにコードをデプロイします。

    $ cd <src>/sample-we-retail-spa-content
    $ mvn -PautoInstallSinglePackage clean install
    
  12. CRXDE-Liteで、/apps/we-retail-journal/react/clientlibs/we-retail-journal-react/js/app.jsを開きます。 app.jsでHelloWorldをクイック検索し、Reactコンポーネントがコンパイル済みアプリに含まれていることを確認します。

    メモ

    app.js は、バンドルされたReactアプリを表示します。コードは人間が読み取れなくなりました。 npm run buildコマンドは、最新のブラウザーで解釈できるコンパイル済みのJavaScriptを出力する最適化されたビルドをトリガーしました。

angularコンポーネントの作成

担当者:フロントエンド開発者

メモ

Reactの開発にのみ関心がある場合は、この節をスキップしてください。

次に、Angularコンポーネントが作成されます。 angularアプリ​モジュール(<src>/aem-sample-we-retail-journal/angular-app)を任意のエディターで開きます。

  1. angular-appフォルダー内で、 srcフォルダーに移動します。 componentsフォルダーを展開して、既存のAngularコンポーネントファイルを表示します。

    Angularファイル構造

  2. componentsフォルダーの下にhelloworldという名前の新しいフォルダーを追加します。 helloworldフォルダーの下に、helloworld.component.css, helloworld.component.html, helloworld.component.tsという名前の新しいファイルを追加します。

    /angular-app
        /src
            /app
                /components
    +                /helloworld
    +                    helloworld.component.css
    +                    helloworld.component.html
    +                    helloworld.component.ts
    
  3. helloworld.component.ts を開きます。angularComponentおよびInputクラスをインポートするimport文を追加します。 styleUrlstemplateUrlhelloworld.component.csshelloworld.component.htmlに向けて、新しいコンポーネントを作成します。 最後に、displayMessageの入力を想定してクラスHelloWorldComponentを書き出します。

    //helloworld.component.ts
    
    import { Component, Input } from '@angular/core';
    
    @Component({
      selector: 'app-helloworld',
      host: { 'class': 'cmp-helloworld' },
      styleUrls:['./helloworld.component.css'],
      templateUrl: './helloworld.component.html',
    })
    
    export class HelloWorldComponent {
      @Input() displayMessage: string;
    }
    
    メモ

    前に作成したSling Modelを思い出すと、getDisplayMessage()​メソッドがあります。 このメソッドのシリアル化されたJSONは、displayMessage​で、Angularアプリで読み上げます。

  4. helloworld.component.htmlを開き、displayMessageプロパティを印刷するh1タグを含めます。

    <h1 *ngIf="displayMessage" class="cmp-helloworld_message">
        {{displayMessage}}
    </h1>
    
  5. コンポーネントの基本的なスタイルを含めるようにhelloworld.component.cssを更新します。

    :host-context {
        display: block;
    };
    
    .cmp-helloworld {
        display:block;
    }
    .cmp-helloworld_message {
        text-align: center;
        color: #ff505e;
        text-transform: unset;
        letter-spacing: unset;
    }
    
  6. helloworld.component.spec.tsを次のテストベッドに更新します。

    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    
    import { HelloWorldComponent } from './helloworld.component';
    
        describe('HelloWorld', () => {
        let component: HelloWorldComponent;
        let fixture: ComponentFixture<HelloWorldComponent>;
    
        beforeEach(async(() => {
            TestBed.configureTestingModule({
            declarations: [ HelloWorldComponent ]
            })
            .compileComponents();
        }));
    
        beforeEach(() => {
            fixture = TestBed.createComponent(HelloWorldComponent);
            component = fixture.componentInstance;
            fixture.detectChanges();
        });
    
        it('should create', () => {
            expect(component).toBeTruthy();
        });
    });
    
  7. 次にsrc/components/mapping.tsを更新し、HelloWorldComponentを含めます。 コンポーネントが設定される前に、AEMエディターでプレースホルダーをマークするHelloWorldEditConfigを追加します。 最後に、MapToヘルパーを使用してAEMコンポーネントをAngularコンポーネントにマッピングする行を追加します。

    // src/components/mapping.ts
    
    import { HelloWorldComponent } from "./helloworld/helloworld.component";
    
    ...
    
    const HelloWorldEditConfig = {
    
        emptyLabel: 'Hello World',
    
        isEmpty: function(props) {
            return !props || !props.displayMessage || props.displayMessage.trim().length < 1;
        }
    };
    
    ...
    
    MapTo('we-retail-journal/components/helloworld')(HelloWorldComponent, HelloWorldEditConfig);
    

    mapping.ts​の完全なコードは、こちらを参照してください。

  8. src/app.module.tsを更新して、NgModule​を更新します。 HelloWorldComponent​を、AppModule​に属する​宣言​として追加します。 また、JSONモデルの処理時にコンパイルされ、アプリに動的に含められるように、 HelloWorldComponentを​entryComponent​として追加します。

    import { HelloWorldComponent } from './components/helloworld/helloworld.component';
    
    ...
    
    @NgModule({
      imports: [BrowserModule.withServerTransition({ appId: 'we-retail-sample-angular' }),
        SpaAngularEditableComponentsModule,
      AngularWeatherWidgetModule.forRoot({
        key: "37375c33ca925949d7ba331e52da661a",
        name: WeatherApiName.OPEN_WEATHER_MAP,
        baseUrl: 'http://api.openweathermap.org/data/2.5'
      }),
        AppRoutingModule,
        BrowserTransferStateModule],
      providers: [ModelManagerService,
        { provide: APP_BASE_HREF, useValue: '/' }],
      declarations: [AppComponent,
        TextComponent,
        ImageComponent,
        WeatherComponent,
        NavigationComponent,
        MenuComponent,
        MainContentComponent,
        HelloWorldComponent],
      entryComponents: [TextComponent,
        ImageComponent,
        WeatherComponent,
        NavigationComponent,
        MainContentComponent,
        HelloWorldComponent],
      bootstrap: [AppComponent]
     })
    

    app.module.ts​の完成したコードは、こちらから参照できます。

  9. Mavenを使用してAEMにコードをデプロイします。

    $ cd <src>/sample-we-retail-spa-content
    $ mvn -PautoInstallSinglePackage clean install
    
  10. CRXDE-Liteで、/apps/we-retail-journal/angular/clientlibs/we-retail-journal-angular/js/main.jsを開きます。 main.jsで​HelloWorld​のクイック検索を実行し、Angularコンポーネントが含まれていることを確認します。

    メモ

    main.js は、バンドルされたAngularアプリです。コードは人間が読み取れなくなりました。 npm run buildコマンドにより、最新のブラウザーで解釈できるコンパイル済みのJavaScriptを出力する最適化ビルドがトリガーされました。

テンプレートの更新

  1. ReactまたはAngular版の編集可能テンプレートに移動します。

  2. メインのレイアウトコンテナを選択し、ポリシーアイコンを選択してポリシーを開きます。

    レイアウトポリシーの選択

    プロパティ > 許可されているコンポーネント​の下で、Custom Components​を検索します。 Hello World​コンポーネントが表示されたら、それを選択します。 右上隅のチェックボックスをクリックして、変更を保存します。

    レイアウトコンテナポリシーの設定

  3. 保存後、HelloWorld​コンポーネントがレイアウトコンテナに許可されたコンポーネントとして表示されます。

    許可されたコンポーネントの更新

    メモ

    AEM 6.5およびAEM 6.4.5のみが、SPA Editorの編集可能なテンプレート機能をサポートしています。 AEM 6.4を使用している場合は、CRXDE Liteを使用して、許可されたコンポーネントのポリシーを手動で設定する必要があります。/conf/we-retail-journal/react/settings/wcm/policies/wcm/foundation/components/responsivegrid/defaultまたは/conf/we-retail-journal/angular/settings/wcm/policies/wcm/foundation/components/responsivegrid/default

    レイアウトコンテナの許可されたコンポーネントの更新されたポリシー設定を示すCRXDE Lite:

    レイアウトコンテナ内の許可されたコンポーネントの更新されたポリシー設定を示すCRXDE Lite

まとめ

  1. angularまたはReactページに移動します。

  2. Hello World​コンポーネントを探し、Hello World​コンポーネントをページにドラッグ&ドロップします。

    hello worldドラッグ&ドロップ

    プレースホルダーが表示されます。

    ハローワールドプレースホルダー

  3. コンポーネントを選択し、ダイアログに「World」または「Your Name」というメッセージを追加します。 変更内容を保存します。

    レンダリングコンポーネント

    「Hello」という文字列は、常にメッセージの先頭に付加されます。 これは、HelloWorld.java Sling Modelのロジックの結果です。

次の手順

HelloWorldコンポーネントの完成したソリューション

トラブルシューティング

Eclipseにプロジェクトを構築できません

エラー: 認識されていない目標の実行に対し We.Retail Journal て、プロジェクトをEclipseに読み込む際にエラーが発生しました。

Execution npm install, Execution npm run build, Execution default-analyze-classes*

eclipseエラーウィザード

解像度:「完了」をクリックして、後で解決します。これにより、チュートリアルが完了することを妨げないでください。

エラー:Reactモジュール( ) react-appは、Mavenビルド中に正常にビルドされません。

解決方法: react-appの下にあ node_modules るフォルダーを 削除してみてください。プロジェクトのルートからApache Mavenコマンドmvn clean install -PautoInstallSinglePackageを再実行します。

AEM内の未満の依存関係

パッケージマネージャーの依存関係のエラー

AEMの依存関係が満たされない場合、AEM Package Manager​または​AEM Webコンソール(Felixコンソール)で、SPAエディター機能が使用できないことを示します。

コンポーネントが表示されない

エラー:デプロイメントが正常に完了し、React/Angularアプリのコンパイル済みバージョンに更新済みコンポーネントがあることを確認した後で helloworld も、コンポーネントをページにドラッグしてもコンポーネントが表示されません。コンポーネントはAEM UIで確認できます。

解像度:ブラウザの履歴/キャッシュをクリアし、新しいブラウザを開くか、匿名モードを使用します。それが機能しない場合は、ローカルのAEMインスタンス上のクライアントライブラリキャッシュを無効にします。 AEMは、効率を上げるために、大規模なクライアントライブラリをキャッシュしようとします。 古いコードがキャッシュされる問題を修正するために、キャッシュを手動で無効にする必要が生じる場合があります。

次の場所に移動します。http://localhost:4502/libs/granite/ui/content/dumplibs.rebuild.htmlを開き、「キャッシュを無効にする」をクリックします。 React/Reactページに戻り、Angularを更新します。

クライアントライブラリの再構築

このページ