Fetch Coral3/Granite composite nested multifield(3 levels) in Design Dialog using Sling Model/Sightly | Community
Skip to main content
Level 2
April 5, 2020
Solved

Fetch Coral3/Granite composite nested multifield(3 levels) in Design Dialog using Sling Model/Sightly

  • April 5, 2020
  • 1 reply
  • 3331 views

hi Team,

 

I am trying to fetch composite nested multifield values under Design Dialog implemented in coral3/Granite. I have tried using sling model but it is NOT able to inject the resource as the multifield values are stored under /etc/designs/PageXYZ/ComponentABC and am trying to call the model from the component path /apps/projectname/components/content/ModuleName/ComponentABC/ComponentABC.html.

 

Nested field storage looks like below:

+-/etc/designs/PageXYZ/ComponentABC

      | +- Item0

           | +-ABCItem

              | +-Item0

                | +-DEFItem

                  | +-Item 0

                      | +-GHIItem

                           | +-Item 0

                           | +-Item 1

 

       | +-Item 1

          | +- Hierarchy Similar to Item0

       | +-Item 2

          | +- Hierarchy Similar to Item0

 

Most of the examples i saw in the community posts are using dialogs and NOT design dialog. So, am NOT able to find the mistake i am doing with the sling modal. I have the flexibility to use JS Use API too, let me know in case of any workarounds related to that. My code is simmilar to this blog post https://helpx.adobe.com/experience-manager/using/aem64_htl_repeat_slingmodel.html but i am trying to retrieve it from design dialog instead of dialog.

 

Request your suggestion/inputs on the same.

This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by Theo_Pendle

Hello, 

That's a very interesting question! 😁 It actually inspired me to write a tutorial on nested Multifields. It is pending publication for the moment, but I'll add it as a comment later when it's out.

However this question goes a bit beyond what's in the tutorial so let me explain.

To access properties from the design dialog, you will need a Sling Model, like this one. Here is the interface:

import org.apache.sling.api.resource.Resource; public interface DemoModel { Resource getPolicy(); }

And here is the implementation:

import com.day.cq.wcm.api.designer.Style; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.ScriptVariable; import org.apache.sling.models.annotations.injectorspecific.Self; import javax.annotation.PostConstruct; @Model( adaptables = SlingHttpServletRequest.class, adapters = DemoModel.class ) @Slf4j public class DemoModelImpl implements DemoModel { @ScriptVariable private Style currentStyle; @1961677 private SlingHttpServletRequest request; @14766979 private Resource policy; @PostConstruct protected void init() { policy = request.getResourceResolver().getResource(currentStyle.getPath()); if (policy == null) { log.error("Could not find policy"); return; } } }

Take a look at the important parts:

1. The @ScriptVariable private Style currentStyle line injects the component's design dialog properties. However in the case of a multifield, you will first need to convert currentStyle into the specific policy node, as I do in the init() method.

The policy Resource then represents the policy node in the JCR. For me its this one:

2. Now that we have the policy resource, we expose it for use in HTL using the getPolicy() method (see interface and @14766979)

Now we can simply access the policy node and iterate over the nested multifield using HTL as you can see below:

<sly data-sly-use.model="com.theopendle.core.models.demo.DemoModel"> <!--/* Get all child resources */--> <div data-sly-list.continentMultifield="${model.policy.getChildren}"> <div data-sly-test="${continentMultifield.name == 'continents'}"> <p>Continents</p> <ul data-sly-list.continent="${continentMultifield.getChildren}"> <li>Name: ${continent.continentName}</li> <li>Countries: <!--/* Get all child resources */--> <div data-sly-list.countryMultifield="${continent.getChildren}"> <!--/* Keep only the countries multifield and iterate over its children */--> <ul data-sly-test="${countryMultifield.name == 'countries'}" data-sly-list.country="${countryMultifield.getChildren}"> <li>Name: ${country.countryName}</li> <li>Code: ${country.code}</li> </ul> </div> </li> </ul> </div> </div> </sly>

 Here is the result:

Hope that helped 👍 

1 reply

Theo_Pendle
Theo_PendleAccepted solution
Level 8
April 6, 2020

Hello, 

That's a very interesting question! 😁 It actually inspired me to write a tutorial on nested Multifields. It is pending publication for the moment, but I'll add it as a comment later when it's out.

However this question goes a bit beyond what's in the tutorial so let me explain.

To access properties from the design dialog, you will need a Sling Model, like this one. Here is the interface:

import org.apache.sling.api.resource.Resource; public interface DemoModel { Resource getPolicy(); }

And here is the implementation:

import com.day.cq.wcm.api.designer.Style; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.models.annotations.Model; import org.apache.sling.models.annotations.injectorspecific.ScriptVariable; import org.apache.sling.models.annotations.injectorspecific.Self; import javax.annotation.PostConstruct; @Model( adaptables = SlingHttpServletRequest.class, adapters = DemoModel.class ) @Slf4j public class DemoModelImpl implements DemoModel { @ScriptVariable private Style currentStyle; @1961677 private SlingHttpServletRequest request; @14766979 private Resource policy; @PostConstruct protected void init() { policy = request.getResourceResolver().getResource(currentStyle.getPath()); if (policy == null) { log.error("Could not find policy"); return; } } }

Take a look at the important parts:

1. The @ScriptVariable private Style currentStyle line injects the component's design dialog properties. However in the case of a multifield, you will first need to convert currentStyle into the specific policy node, as I do in the init() method.

The policy Resource then represents the policy node in the JCR. For me its this one:

2. Now that we have the policy resource, we expose it for use in HTL using the getPolicy() method (see interface and @14766979)

Now we can simply access the policy node and iterate over the nested multifield using HTL as you can see below:

<sly data-sly-use.model="com.theopendle.core.models.demo.DemoModel"> <!--/* Get all child resources */--> <div data-sly-list.continentMultifield="${model.policy.getChildren}"> <div data-sly-test="${continentMultifield.name == 'continents'}"> <p>Continents</p> <ul data-sly-list.continent="${continentMultifield.getChildren}"> <li>Name: ${continent.continentName}</li> <li>Countries: <!--/* Get all child resources */--> <div data-sly-list.countryMultifield="${continent.getChildren}"> <!--/* Keep only the countries multifield and iterate over its children */--> <ul data-sly-test="${countryMultifield.name == 'countries'}" data-sly-list.country="${countryMultifield.getChildren}"> <li>Name: ${country.countryName}</li> <li>Code: ${country.code}</li> </ul> </div> </li> </ul> </div> </div> </sly>

 Here is the result:

Hope that helped 👍 

abhifoyouAuthor
Level 2
April 6, 2020

Thank you so much theop76211228 for your reply. I have already tried this approach of getting the currentStyle using @ScriptVariable. But whenever, i try to use that in HTL, i get an error saying "model cannot be correctly instantiated by the use api". Once I remove the @ScriptVariable , page loads properly. NOT sure what is this happening. Any inputs on that ?

?

 

Also, we are still NOT using editable templates so we do not have a policy node under /etc/designs. The storage of the multi-field is something like below.

Can I get the multi-field values like ${TopMultifield.getChildren} in HTL ?? What would be init method look like then ?

+-/etc/designs

  | +PageXYZ

      | +ComponentABC

       | +TopMultifield

         | +- Item0

           | +-ABCItem

              | +-Item0

                | +-DEFItem

                  | +-Item 0

                      | +-GHIItem

                           | +-Item 0

                           | +-Item 1

 

Sorry, too many questions. 😑