擴充核心元件 extend-component
瞭解如何擴充要與AEM SPA Editor搭配使用的現有核心元件。 瞭解如何擴充現有元件是一項強大的技術,可自訂和擴充AEM SPA Editor實作的功能。
目標
- 使用其他屬性和內容擴充現有的核心元件。
- 瞭解使用
sling:resourceSuperType的元件繼承基本知識。 - 瞭解如何為Sling模型使用委派模式以重複使用現有邏輯和功能。
您將要建置的內容
在本章中,已建立新的Card元件。 Card元件會擴充影像核心元件,新增其他內容欄位,例如「標題」和「Call to action」按鈕,以針對SPA內的其他內容執行Teaser角色。
先決條件
檢閱設定本機開發環境所需的工具與指示。
取得程式碼
-
透過Git下載本教學課程的起點:
code language-shell $ git clone git@github.com:adobe/aem-guides-wknd-spa.git $ cd aem-guides-wknd-spa $ git checkout Angular/extend-component-start -
使用Maven將程式碼庫部署到本機AEM執行個體:
code language-shell $ mvn clean install -PautoInstallSinglePackage如果使用AEM 6.x,請新增
classic設定檔:code language-shell $ mvn clean install -PautoInstallSinglePackage -Pclassic -
安裝傳統WKND參考站台的完成套件。 由WKND參考網站提供的影像會在WKND SPA上重複使用。 可以使用AEM的封裝管理員來安裝封裝。
您隨時可以在 GitHub 上檢視完成的程式碼,或透過切換到分支 Angular/extend-component-solution 在本機查看程式碼。
檢查初始卡片實施
章節起始程式碼已提供初始卡片元件。 檢查卡片實作的起點。
-
在您選擇的IDE中,開啟
ui.apps模組。 -
瀏覽至
ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/card並檢視.content.xml檔案。
code language-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="Card" sling:resourceSuperType="wknd-spa-angular/components/image" componentGroup="WKND SPA Angular - Content"/>屬性
sling:resourceSuperType指向wknd-spa-angular/components/image,表示Card元件繼承了WKND SPA影像元件的功能。 -
檢查檔案
ui.apps/src/main/content/jcr_root/apps/wknd-spa-angular/components/image/.content.xml:code language-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:resourceSuperType指向core/wcm/components/image/v2/image。 這表示WKND SPA影像元件繼承了核心元件影像的功能。也稱為Proxy模式 Sling資源繼承是一種強大的設計模式,可讓子元件繼承功能並在需要時擴充/覆寫行為。 Sling繼承支援多個層級的繼承,所以新
Card元件最終會繼承核心元件影像的功能。許多開發團隊都會努力做到自我(請勿重複這點)。 Sling繼承可讓AEM實現此目標。
-
在
card資料夾下,開啟檔案_cq_dialog/.content.xml。此檔案是
Card元件的元件對話方塊定義。 如果使用Sling繼承,則可以使用Sling資源合併器的功能來覆寫或擴充對話方塊的部分。 在此範例中,對話方塊中已新增索引標籤,以從作者擷取其他資料並填入卡片元件。sling:orderBefore之類的屬性可讓開發人員選擇插入新標籤或表單欄位的位置。 在此情況下,Text索引標籤會插入asset索引標籤之前。 若要充分利用Sling Resource Merger,請務必瞭解影像元件對話方塊的原始對話方塊節點結構。 -
在
card資料夾下,開啟檔案_cq_editConfig.xml。 此檔案會指定AEM編寫UI中的拖放行為。 擴充影像元件時,資源型別必須符合元件本身。 檢閱<parameters>節點:code language-xml <parameters jcr:primaryType="nt:unstructured" sling:resourceType="wknd-spa-angular/components/card" imageCrop="" imageMap="" imageRotate=""/>大部分元件不需要
cq:editConfig,影像和影像元件的子系下階是例外。 -
在IDE切換至
ui.frontend模組,瀏覽至ui.frontend/src/app/components/card:
-
檢查檔案
card.component.ts。元件已經使用標準
MapTo函式截斷,以對應至AEMCard元件。code language-js MapTo('wknd-spa-angular/components/card')(CardComponent, CardEditConfig);檢閱類別中
src、alt和title的三個@Input引數。 這些是AEM元件中對應至Angular元件的預期JSON值。 -
開啟檔案
card.component.html:code language-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編輯器中的功能。 若要檢視初始Card元件,需要更新範本原則。
-
將入門程式碼部署到AEM的本機執行個體(如果尚未部署):
code language-shell $ cd aem-guides-wknd-spa $ mvn clean install -PautoInstallSinglePackage -
更新配置容器的原則以將新的
Card元件新增為允許的元件:
儲存原則的變更,並將
Card元件視為允許的元件:
作者初始卡片元件
接下來,使用AEM SPA編輯器編寫Card元件。
-
導覽至http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html。
-
在
Edit模式中,將Card元件新增至Layout Container:
-
將影像從資產尋找器拖放至
Card元件上:
-
開啟
Card元件對話方塊並注意已新增 文字 索引標籤。 -
在 文字 索引標籤上輸入下列值:
卡片路徑 — 在SPA首頁下方選擇頁面。
CTA文字 - 「瞭解詳情」
卡片標題 — 留空
從連結的頁面取得標題 — 勾選核取方塊以表示True。
-
更新 資產中繼資料 索引標籤以新增 替代文字 和 標題 的值。
更新對話方塊後,目前沒有其他變更顯示。 若要將新欄位公開給Angular元件,我們需要更新
Card元件的Sling模型。 -
開啟新索引標籤並導覽至CRXDE-Lite。 檢查
/content/wknd-spa-angular/us/en/home/jcr:content/root/responsivegrid下的內容節點以尋找Card元件內容。
Observe that properties
cardPath,ctaText,titleFromPageare persisted by the dialog.
Update Card Sling Model
To ultimately expose the values from the component dialog to the Angular component, we need to update the Sling Model that populates the JSON for the Card component. We also have the opportunity to implement two pieces of business logic:
- If
titleFromPageto true, return the title of the page specified bycardPathotherwise return the value ofcardTitletextfield. - Return the last modified date of the page specified by
cardPath.
Return to the IDE of your choice and open the core module.
-
在
core/src/main/java/com/adobe/aem/guides/wknd/spa/angular/core/models/Card.java開啟檔案Card.java。Observe that the
Cardinterface currently extendscom.adobe.cq.wcm.core.components.models.Imageand therefore inherits the methods of theImageinterface. TheImageinterface already extends theComponentExporterinterface which allows the Sling Model to be exported as JSON and mapped by the SPA editor. Therefore we do not need to explicitly extendComponentExporterinterface like we did in the Custom Component chapter. -
Add the following methods to the interface:
code language-java @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(); }These methods are exposed via the JSON model API and passed to the Angular component.
-
開啟
CardImpl.java。 This is the implementation ofCard.javainterface. This implementation has been partially stubbed out to accelerate the tutorial. Notice the use of the@Modeland@Exporterannotations to ensure that the Sling Model is able to be serialized as JSON via the Sling Model Exporter.CardImpl.javaalso uses the Delegation pattern for Sling Models to avoid rewriting the logic from the Image Core Component. -
Observe the following lines:
code language-java @Self @Via(type = ResourceSuperType.class) private Image image;The above annotation instantiates an Image object named
imagebased on thesling:resourceSuperTypeinheritance of theCardcomponent.code language-java @Override public String getSrc() { return null != image ? image.getSrc() : null; }It is then possible to simply use the
imageobject to implement methods defined by theImageinterface, without having to write the logic ourselves. This technique is used forgetSrc(),getAlt(), andgetTitle(). -
Next, implement the
initModel()method to initiate a private variablecardPagebased on the value ofcardPathcode language-java @PostConstruct public void initModel() { if(StringUtils.isNotBlank(cardPath) && pageManager != null) { cardPage = pageManager.getPage(this.cardPath); } }The
@PostConstruct initModel()is called when the Sling Model is initialized, therefore it is a good opportunity to initialize objects that may be used by other methods in the model. ThepageManageris one of several Java™ backed global objects made available to Sling Models via the@ScriptVariableannotation. getPage方法接受路徑並傳回AEM Page物件,如果路徑未指向有效頁面,則傳回null。這會初始化
cardPage變數,其他新方法會使用此變數來傳回基礎連結頁面的相關資料。 -
檢閱已對映至作者對話方塊所儲存JCR屬性的全域變數。
@ValueMapValue註解是用來自動執行對應。code language-java @ValueMapValue private String cardPath; @ValueMapValue private String ctaText; @ValueMapValue private boolean titleFromPage; @ValueMapValue private String cardTitle;這些變數可用來實作
Card.java介面的其他方法。 -
實作
Card.java介面中定義的其他方法:code language-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; }note note NOTE 您可以在🔗檢視完成的CardImpl.java。 -
開啟終端機視窗,並使用
core目錄中的MavenautoInstallBundle設定檔僅部署core模組的更新。code language-shell $ cd core/ $ mvn clean install -PautoInstallBundle如果使用AEM 6.x,請新增
classic設定檔。 -
檢視JSON模型回應: http://localhost:4502/content/wknd-spa-angular/us/en.model.json,並搜尋
wknd-spa-angular/components/card:code language-json "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" }請注意,更新
CardImplSling模型中的方法後,JSON模型已更新為其他索引鍵/值組。
更新Angular元件
現在JSON模型已填入ctaLinkURL、ctaText、cardTitle和cardLastModified的新屬性,我們可以更新Angular元件以顯示這些屬性。
-
返回IDE並開啟
ui.frontend模組。 您可以選擇從新的終端機視窗啟動webpack開發伺服器,即時檢視變更:code language-shell $ cd ui.frontend $ npm install $ npm start -
在
ui.frontend/src/app/components/card/card.component.ts開啟card.component.ts。 新增其他@Input註解以擷取新模型:code language-diff 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; -
新增檢查Call to action是否準備就緒的方法,以及根據
cardLastModified輸入傳回日期/時間字串的方法:code language-js 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; } ... } -
開啟
card.component.html並新增下列標籤以顯示標題、call to action和上次修改日期:code language-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規則,以設定標題、call to action和上次修改日期的樣式。note note NOTE 您可以在此檢視已完成的Angular卡元件程式碼。 -
使用Maven從專案的根將完整變更部署到AEM:
code language-shell $ cd aem-guides-wknd-spa $ mvn clean install -PautoInstallSinglePackage -
導覽至http://localhost:4502/editor.html/content/wknd-spa-angular/us/en/home.html檢視更新的元件:
-
您應該能夠重新編寫現有內容以建立類似下列的頁面:
恭喜! congratulations
Congratulations, you learned how to extend an AEM component and how Sling Models and dialogs work with the JSON model.
您隨時可以在 GitHub 上檢視完成的程式碼,或透過切換到分支 Angular/extend-component-solution 在本機查看程式碼。