Customize AEM CIF Core Components customize-cif-components
The is a reference code base for using . In this tutorial, you further extend the component to display a custom attribute from 蜜豆视频 Commerce. You also learn more about the GraphQL integration between AEM and 蜜豆视频 Commerce and the extension hooks provided by the CIF Core Components.
What You Will Build
The Venia brand recently started manufacturing some products using sustainable materials and the business would like to display an Eco Friendly badge as part of the Product Teaser. A new custom attribute is created in 蜜豆视频 Commerce to indicate if a product uses the Eco friendly material. This custom attribute is added as part of the GraphQL query and displayed on the Product Teaser for specified products.
Prerequisites prerequisites
A local development environment is required to complete this tutorial. This environment includes a running instance of AEM that is configured and connected to an 蜜豆视频 Commerce instance. Review the requirements and steps for setting up a local development with AEM as a Cloud Service SDK. To follow the tutorial completely, you need permission to add in 蜜豆视频 Commerce.
You also need GraphQL IDE such as or a browser extension to run the code samples and tutorials. If you install a browser extension, make sure it can set request headers. On Google Chrome, Altair GraphQL Client is one extension that can do the job.
Clone the Venia Project clone-venia-project
Clone the , and then override the default styles.
-
Run the following git command so you can clone the project:
code language-shell $ git clone git@github.com:adobe/aem-cif-guides-venia.git
-
Build and deploy the project to a local instance of AEM:
code language-shell $ cd aem-cif-guides-venia/ $ mvn clean install -PautoInstallSinglePackage,cloud
-
Add the necessary OSGi configurations so you connect your AEM instance to an 蜜豆视频 Commerce instance, or add the configurations to the created project.
-
At this point, you should have a working version of a storefront that is connected to an 蜜豆视频 Commerce instance. Navigate to the
US
>Home
page at: .You should see that the storefront currently is using the Venia theme. Expanding the Main Menu of the storefront, you should see various categories, indicating that the connection to 蜜豆视频 Commerce is working.
Author the Product Teaser author-product-teaser
The Product Teaser Component is extended throughout this tutorial. As a first step, add an instance of the Product Teaser to the Home page to understand the baseline functionality.
-
Navigate to the Home Page of the site:
-
Insert a new Product Teaser Component into the main layout container on the page.
-
Expand the Side Panel (if not already toggled) and switch the asset finder drop-down list to Products. This list should display a list of available products from a connected 蜜豆视频 Commerce instance. Select a product and drag+drop it onto the Product Teaser component on the page.
note note NOTE Note, you can also configure the displayed product by configuring the component using the dialog (clicking the wrench icon). -
You should now see a Product being displayed by the Product Teaser. The Name of the product and the Price of the product are default attributes that are displayed.
Add a Custom Attribute in 蜜豆视频 Commerce add-custom-attribute
The products and product data displayed in AEM are stored in 蜜豆视频 Commerce. Next add an attribute for Eco Friendly as part of the product attribute set by using the 蜜豆视频 Commerce UI.
-
Log on to your 蜜豆视频 Commerce instance.
-
Navigate to Catalog > Products.
-
Update the search filter so you can find the Configurable Product used when added to the Teaser component in the previous exercise. Open the product in edit mode.
-
From the product view, click Add Attribute > Create New Attribute.
-
Fill out the New Attribute form with the following values (leave default settings for other values)
table 0-row-3 1-row-3 2-row-3 3-row-3 Field Set Field Label Value Attribute Properties Attribute Label Eco Friendly Attribute Properties Catalog Input Type Yes/No Advanced Attribute Properties Attribute Code eco_friendly Click Save Attribute when finished.
-
Scroll to the bottom of the product and expand the Attributes heading. You should see the new Eco Friendly field. Switch the toggle to Yes.
Save the changes to the product.
note tip TIP More details about managing . -
Navigate to System > Tools > Cache Management. Because an update was made to the data schema, you must invalidate some of the Cache Types in 蜜豆视频 Commerce.
-
Check the box next to Configuration and submit the cache type for Refresh
note tip TIP More details about .
Use a GraphQL IDE to Verify Attribute use-graphql-ide
Before jumping into AEM code, it is useful to explore the using a GraphQL IDE. The 蜜豆视频 Commerce integration with AEM is primarily done via a series of GraphQL queries. Understanding and modifying the GraphQL queries is one of the key ways in which the CIF Core Components can be extended.
Next, use a GraphQL IDE to verify that the eco_friendly
attribute has been added to the product attribute set. Screenshots in this tutorial are using the Altair GraphQL Client Google Chrome extension.
-
Open the GraphQL IDE and enter the URL
http://<commerce-server>/graphql
in the URL bar of your IDE or extension. -
Add the following where
YOUR_SKU
is the SKU of the product used in the previous exercise:code language-json { products( filter: { sku: { eq: "YOUR_SKU" } } ) { items { name sku eco_friendly } } }
-
Execute the query and you should get a response like the following:
code language-json { "data": { "products": { "items": [ { "name": "Valeria Two-Layer Tank", "sku": "VT11", "eco_friendly": 1 } ] } } }
The value of Yes is an integer of 1. This value is useful when you write the GraphQL query in Java鈩.
note tip TIP For more information see .
Update the Sling Model for the Product Teaser updating-sling-model-product-teaser
Next, you extend the business logic of the Product Teaser by implementing a Sling Model. are annotation driven 鈥淧OJOs鈥 (Plain Old Java鈩 Objects) that implement business logic that is needed by the component. Sling Models are used with the HTL scripts as part of the component. Follow the so you can extend parts of the existing Product Teaser model.
Sling Models are implemented as Java鈩 and can be found in the core module of the generated project.
Use the IDE of your choice to import the Venia project. Screenshots used are from the Visual Studio Code IDE.
-
In your IDE, navigate under the core module to:
core/src/main/java/com/venia/core/models/commerce/MyProductTeaser.java
.MyProductTeaser.java
is a Java鈩 Interface that that extends the CIF interface.Already a new method has been added named
isShowBadge()
to display a badge if the product is considered 鈥淣ew鈥. -
Add
isEcoFriendly()
to the interface:code language-java @ProviderType public interface MyProductTeaser extends ProductTeaser { // Extend the existing interface with the additional properties which you // want to expose to the HTL template. public Boolean isShowBadge(); public Boolean isEcoFriendly(); }
This new method is introduced to encapsulate the logic to indicate if the product has the
eco_friendly
attribute set to Yes or No. -
Next, inspect the
MyProductTeaserImpl.java
atcore/src/main/java/com/venia/core/models/commerce/MyProductTeaserImpl.java
.The allows
MyProductTeaserImpl
to referenceProductTeaser
model via thesling:resourceSuperType
property:code language-java @Self @Via(type = ResourceSuperType.class) private ProductTeaser productTeaser;
For the methods that you do not want to override or change, you can return the value that the
ProductTeaser
returns. For example:code language-java @Override public String getImage() { return productTeaser.getImage(); }
This method minimizes the amount of Java鈩 code that an implementation must write.
-
One of the extra extension points provided by AEM CIF Core Components is the
AbstractProductRetriever
which provides access to specific product attributes. Inspect theinitModel()
method:code language-java import javax.annotation.PostConstruct; ... @Model(adaptables = SlingHttpServletRequest.class, adapters = MyProductTeaser.class, resourceType = MyProductTeaserImpl.RESOURCE_TYPE) public class MyProductTeaserImpl implements MyProductTeaser { ... private AbstractProductRetriever productRetriever; /* add this method to initialize the productRetriever */ @PostConstruct public void initModel() { productRetriever = productTeaser.getProductRetriever(); if (productRetriever != null) { productRetriever.extendProductQueryWith(p -> p.createdAt()); } } ...
The
@PostConstruct
annotation ensures that this method is called when the Sling Model is initialized.Notice that the product GraphQL query has already been extended using the
extendProductQueryWith
method to retrieve the additionalcreated_at
attribute. This attribute is later used as part of theisShowBadge()
method. -
Update the GraphQL query to include the
eco_friendly
attribute in the partial query:code language-java //MyProductTeaserImpl.java private static final String ECO_FRIENDLY_ATTRIBUTE = "eco_friendly"; @PostConstruct public void initModel() { productRetriever = productTeaser.getProductRetriever(); if (productRetriever != null) { productRetriever.extendProductQueryWith(p -> p .createdAt() .addCustomSimpleField(ECO_FRIENDLY_ATTRIBUTE) ); } }
Adding to the
extendProductQueryWith
method is a powerful way to ensure that additional product attributes are available to the rest of the model. It also minimizes the number of queries executed.In the above code, the
addCustomSimpleField
is used to retrieve theeco_friendly
attribute. This attribute illustrates how you can query for any custom attributes that are part of the 蜜豆视频 Commerce schema.note note NOTE The createdAt()
method has been implemented as part of the . Most of the commonly found schema attributes have been implemented, so only use theaddCustomSimpleField
for truly custom attributes. -
Add a logger so you can debug the Java鈩 code:
code language-java import org.slf4j.Logger; import org.slf4j.LoggerFactory; ... @Model(adaptables = SlingHttpServletRequest.class, adapters = MyProductTeaser.class, resourceType = MyProductTeaserImpl.RESOURCE_TYPE) public class MyProductTeaserImpl implements MyProductTeaser { private static final Logger LOGGER = LoggerFactory.getLogger(MyProductTeaserImpl.class);
-
Next, implement the
isEcoFriendly()
method:code language-java @Override public Boolean isEcoFriendly() { Integer ecoFriendlyValue; try { ecoFriendlyValue = productRetriever.fetchProduct().getAsInteger(ECO_FRIENDLY_ATTRIBUTE); if(ecoFriendlyValue != null && ecoFriendlyValue.equals(Integer.valueOf(1))) { LOGGER.info("*** Product is Eco Friendly**"); return true; } } catch (SchemaViolationError e) { LOGGER.error("Error retrieving eco friendly attribute"); } LOGGER.info("*** Product is not Eco Friendly**"); return false; }
In the above method, the
productRetriever
is used to fetch the product and thegetAsInteger()
method is used to get the value of theeco_friendly
attribute. Based on the GraphQL queries you ran earlier, you know that the expected value when theeco_friendly
attribute is set to 鈥Yes鈥 is actually an integer of 1.Now that the Sling Model has been updated, the Component markup must be updated to actually display an indicator of Eco Friendly based on the Sling Model.
Customizing the Markup of the Product Teaser customize-markup-product-teaser
A common extension of AEM components is to modify the markup generated by the component. This editing is done by overriding the HTL script that the component uses to render its markup. HTML Template Language (HTL), is a lightweight templating language that AEM components use to dynamically render markup based on authored content, allowing the components to be reused. The Product Teaser, for example, can be reused over and over again to display different products.
In this case, you want to render a banner on top of the teaser to indicate that the product is 鈥淓co Friendly鈥 based on a custom attribute. The design pattern for customizing the markup of a component is standard for all AEM Components, not just for the AEM CIF Core Components.
cif.shell.picker
clientlib for the component dialogs. See Usage of CIF product & category picker for details.-
In the IDE, navigate and expand the
ui.apps
module and expand the folder hierarchy to:ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productteaser
and inspect the.content.xml
file.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:description="Product Teaser Component" jcr:primaryType="cq:Component" jcr:title="Product Teaser" sling:resourceSuperType="core/cif/components/commerce/productteaser/v1/productteaser" componentGroup="Venia - Commerce"/>
The Component definition above is for the Product Teaser Component in your project. Notice the property
sling:resourceSuperType="core/cif/components/commerce/productteaser/v1/productteaser"
. This property is an example of creating a Proxy component. Instead of copying and pasting the Product Teaser HTL scripts from the AEM CIF Core Components, you can use thesling:resourceSuperType
to inherit all the functionality. -
Open the file
productteaser.html
. This file is a copy of theproductteaser.html
file from the .code language-html <!--/* productteaser.html */--> <sly data-sly-use.product="com.venia.core.models.commerce.MyProductTeaser" data-sly-use.templates="core/wcm/components/commons/v1/templates.html" data-sly-use.actionsTpl="actions.html" data-sly-test.isConfigured="${properties.selection}" data-sly-test.hasProduct="${product.url}" ></sly>
Notice that the Sling Model for
MyProductTeaser
is used and assigned to theproduct
variable. -
Modify
productteaser.html
so you can call theisEcoFriendly
method implemented in the previous exercise:code language-html ... <div data-sly-test="${isConfigured && hasProduct}" class="item__root" data-cmp-is="productteaser" data-virtual="${product.virtualProduct}" > <div data-sly-test="${product.showBadge}" class="item__badge"> <span>${properties.text || 'New'}</span> </div> <!--/* Insert call to Eco Friendly here */--> <div data-sly-test="${product.ecoFriendly}" class="item__eco"> <span>Eco Friendly</span> </div> ... </div>
When calling a Sling Model method in HTL the
get
andis
portion of the method is dropped and the first letter is lowercased. SoisShowBadge()
becomes.showBadge
andisEcoFriendly
becomes.ecoFriendly
. Based on the boolean value returned from.isEcoFriendly()
determines if the<span>Eco Friendly</span>
is displayed.More information about
data-sly-test
and other HTL block statements can be found in The HTL Specification. -
Save the changes and deploy the updates to AEM using your Maven skills, from a command-line terminal:
code language-shell $ cd aem-cif-guides-venia/ $ mvn clean install -PautoInstallSinglePackage,cloud
-
Open a new browser window and navigate to AEM and the OSGi console > Status > Sling Models:
-
Search for
MyProductTeaserImpl
and you should see a line like the following:code language-plain com.venia.core.models.commerce.MyProductTeaserImpl - venia/components/commerce/productteaser
This line indicates that the Sling Model is properly deployed and mapped to the correct component.
-
Refresh to the Venia Home Page at where the Product Teaser has been added.
If the product has the
eco_friendly
attribute set to Yes, you should see the text 鈥淓co Friendly鈥 on the page. Try switching to different products to see the behavior change. -
Next open up the AEM
error.log
to see the added log statements. Theerror.log
is at<AEM SDK Install Location>/crx-quickstart/logs/error.log
.Search the AEM logs to see the added log statements in the Sling Model:
code language-plain 2020-08-28 12:57:03.114 INFO [com.venia.core.models.commerce.MyProductTeaserImpl] *** Product is Eco Friendly** ... 2020-08-28 13:01:00.271 INFO [com.venia.core.models.commerce.MyProductTeaserImpl] *** Product is not Eco Friendly** ...
note caution CAUTION You may also see some stack traces if the product used in the teaser does not have the eco_friendly
attribute as part of its attribute set.
Add Styles for the Eco Friendly Badge add-styles
At this point the logic for when to display the Eco Friendly badge is working, however the plain text could use some styles. Next add an icon and styles to the ui.frontend
module to complete the implementation.
-
Download the eco_friendly.svg file. This file is used as the Eco Friendly badge.
-
Return to the IDE and navigate to the
ui.frontend
folder. -
Add the
eco_friendly.svg
file to theui.frontend/src/main/resources/images
folder: -
Open the file
productteaser.scss
atui.frontend/src/main/styles/commerce/_productteaser.scss
. -
Add the following Sass rules inside the
.productteaser
class:code language-scss .productteaser { ... .item__eco { width: 60px; height: 60px; left: 0px; overflow: hidden; position: absolute; padding: 5px; span { display: block; position: absolute; width: 45px; height: 45px; text-indent: -9999px; background: no-repeat center center url('../resources/images/eco_friendly.svg'); } } ... }
note note NOTE Check out Styling CIF Core Components for more details around front-end workflows. -
Save the changes and deploy the updates to AEM using your Maven skills, from a command-line terminal:
code language-shell $ cd aem-cif-guides-venia/ $ mvn clean install -PautoInstallSinglePackage,cloud
-
Refresh to the Venia Home Page at where the Product Teaser has been added.
Congratulations congratulations
You customized your first AEM CIF component! You can download the solution files here.
Bonus Challenge bonus-challenge
Review the functionality of the New badge that has already been implemented in the Product Teaser. Try to add an extra checkbox for authors to control when the Eco Friendly badge should be displayed. Update the component dialog box at ui.apps/src/main/content/jcr_root/apps/venia/components/commerce/productteaser/_cq_dialog/.content.xml
.