Hi,
I ve got a AEM Component B, which I can drag into a page and configure it through Edit Dialog. This configured Values are loaded into SlingModelB, which is used in html code of Component B.
Now, I ve got another use case...
I ve got a AEM Component A, which needs to dynamically include AEM Component B in html file of Component A.
How to create dynamically a SlingModelB and pass it to some HTL Command to render AEM Component B inside of Component A ?
Hope somebody is able to help me.
Thanks a lot for your support in advance.
Topics help categorize Community content and increase your ability to discover relevant content.
Views
Replies
Total Likes
Hi @vhochsteinTef ,
To dynamically include Component B within Component A and pass a custom instance of SlingModelB to it, you can follow these steps:
1. Create Component A’s Sling Model (SlingModelA)
Component A will need a Sling Model to manage the logic of dynamically including Component B.
package com.example.core.models;
import com.example.core.models.SlingModelB;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
import javax.inject.Inject;
@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class SlingModelA {
@Self
private Resource resource;
@Self
private SlingModelB slingModelB;
public SlingModelB getSlingModelB() {
// Logic to initialize and customize SlingModelB
return slingModelB;
}
}
2. Component A HTL (HTML)
In the HTL of Component A, use the data-sly-resource attribute to dynamically include Component B and pass SlingModelB. There are 2 examples how you can reuse sling models.
<!-- componentA.html -->
<div class="component-a">
<!-- Other HTML -->
<!-- How to include component B from A -->
<div data-sly-resource="${'path/to/componentB' @ resourceType='example/components/componentB'}">
</div>
<sly data-sly-use.slingModelA="com.example.core.models.SlingModelA"></sly>
<!-- Example 1 -->
<sly data-sly-use.slingModelB="com.example.core.models.SlingModelB"></sly>
<!-- Example 2 -->
<sly data-sly-set.slingModelBFromA="${slingModelA.slingModelB}"></sly>
<!-- Other HTML -->
</div>
3. Component B Sling Model (SlingModelB)
Ensure SlingModelB is structured to accept dynamic data, possibly through constructor injection.
package com.example.core.models;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.injectorspecific.ValueMapValue;
@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class SlingModelB {
@ValueMapValue
private String property1;
// Other properties and logic
public String getProperty1() {
return property1;
}
// Other getters
}
4. Component B HTL (HTML)
Render the data passed from Component A inside Component B.
<!-- componentB.html -->
<div class="component-b">
<p>${slingModelB.property1}</p>
<!-- Render other properties of SlingModelB -->
</div>
Hi Konstantyn,
Thanks a lot for your guidance. Really appreciated.
I think I m still missing the major understanding how that link between data-sly-resource and data-sly-use is actually working.
Let me adjust the java model A code a little bit. It now returns a list of SlingModelBs
how would htl look like to render that list of SlingModelsBs in htl of SlingModelA ?
package com.example.core.models;
import com.example.core.models.SlingModelB;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.injectorspecific.Self;
import javax.inject.Inject;
@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class SlingModelA {
@Self
private Resource resource;
@Self
private List<SlingModelB> slingModelBs;
public List<SlingModelB> getSlingModelBs() {
// Logic to initialize and customize SlingModelBs
return slingModelBs;
}
}
Thanks a lot for your support in advance.
--
Volker
Hi @vhochsteinTef
Please check example here, where Text-and-Image component include text and image components based on condition :
Hi Arun,
in that example I do not understand how you can pass individual attributes for eg image resource.
--
Volker
Hi,
Lets consider you have a Component i.e. LinkModel(A), here is the sling Model for link : https://github.com/arunpatidar02/com.aemlab.junitapp/blob/master/core/src/main/java/com/aemlab/junit...
Now your component LinkCollectionModel(B) use list of LinkModel(A) in the Component
@Model(adaptables = Resource.class, defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)
public class LinkCollectionModel {
@inject
private Resource linkcollections;
private List<LinkModel> linkCollectionList = Collections.emptyList();
@PostConstruct
protected void init() {
if (linkcollections != null) {
linkCollectionList = ModelHelper.getChildrenModels(linkcollections, LinkModel.class);
}
}
public List<LinkModel> getLinkCollectionList() {
return new ArrayList<LinkModel>(linkCollectionList);
}
}
ModelHelper :
HTL
link.html
link-collection.html
link-template.html
<!-- Link: Component A -->
<div data-sly-use.link="com.aemlab.junit.core.models.LinkModel">
<sly data-sly-use.linkTemplate="link.html">
<sly data-sly-call="${linkTemplate.link @ link=link}"></sly>
</sly>
</div>
<!-- LinkCollection: Component B -->
<div data-sly-use.linkCollection="com.aemlab.junit.core.models.LinkCollectionModel" class="cmp-link-collection__links-container">
<ul data-sly-list.link="${linkCollection.linkCollectionList}">
<sly data-sly-use.linkTemplate="link.html">
<li>
<sly data-sly-call="${linkTemplate.link @ link=link}"></sly>
</li>
</sly>
</ul>
</div>
<!-- Link template -->
<sly data-sly-template.link="${@ link}">
<div class="cmp__link">
<a class="cmp-__link"
href="${link.lnHref @ context='uri'}"
title="${link.lnTitle}"
target="${link.lnTarget}">
${link.lnTitle}
</a>
</div>
</sly>
Hi Arun,
thanks a lot, in my use case I do not have a template I have AEM Component.
How to adapt your
<sly data-sly-call="${linkTemplate.link @ link=link}"></sly>
to do the same with AEM Component B, so passing current Link Model to Component B ?
thanks a lot for your support in advance.
Hi @vhochsteinTef
You need to then use data-sly-resource to map a resource with another component.
<section data-sly-resource="${link.path @ resourceType='my/resource/type'}"></section>
Hi
ok that would be easy... just to clarify..
Following code will be my solution right ?
<!-- LinkCollection: Component B -->
<div data-sly-use.linkCollection="com.aemlab.junit.core.models.LinkCollectionModel" class="cmp-link-collection__links-container">
<ul data-sly-list.link="${linkCollection.linkCollectionList}">
<li>
<sly data-sly-resource="${link.path @ resourceType='my/resource/type'}"></sly>
</li>
</sly>
</ul>
</div>
Hi @vhochsteinTef
The above code is not gonna be your solution, the code is just for reference/demo to show how multiitem can be parsed and mapped to another component.
You need to refactor the HTL and test if something does not work with above HTL.
But concept is gonna be the same.
Hi Arun,
did not work out..
Model B is not passed to sly resource at least it looks like, cause just empty "html" of Component B is rendered by that call...
tried both these variations...
Views
Replies
Total Likes
Hi @vhochsteinTef
You need to debug this, to make sue the paths are correct.
Please check example here :
Views
Replies
Total Likes
Hi Arun,
I am sure that correct html file of Model B is called, because that is rendered, just without any attribute Values of Model B.
In your examples given ....
item.path
what is that doing... just the property path of item is passed ?
I need the whole SlingModel B including all attributes
Views
Replies
Total Likes
@vhochsteinTef Did you find the suggestions helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you've discovered a solution yourself, we would appreciate it if you could share it with the community. Thank you!
Views
Replies
Total Likes
Views
Likes
Replies