Expand my Community achievements bar.

SOLVED

AEM Multi-fields not returning from Sling Model

Avatar

Level 3

Hello AEM Heads!

 

I have been wracking my brain on this for well over a week now and figured I'd reach out and try to see what I am doing wrong. I have set-up a multi-field in my cq:dialog for this component and, as you can see, they are being are stored correctly in crxdelite, but when I have tried to pull them out and into the HTML, I am not seeing them being displayed. You can see the code below, where it is being called, the Model I have created, and how it's being stored. I did check the logs and see that I was receiving an Error from the Model and that the multi-field size was 0, however, since I am getting the "cards" item in my model, I'm not sure why it's not counting those?

 

Just not really sure what to do as I've tried a lot of tweaking to no luck. Any insight would be greatly appreciated!!

 

Edit: Removing third party code

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

First of all you should not make your sling model adaptables to SlingHttpServletRequest specially to get value from multifiled. then you made a mistake by trying to directly inject your resource for multifield. These are some mistake you have done prima-facie.

Please go thru the below article which fits 100% in your requirement.

https://helpx.adobe.com/experience-manager/using/aem64_htl_repeat_slingmodel.html

Just see the sling model 

 

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
 
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import org.apache.sling.settings.SlingSettingsService;
 
@Model(adaptables = Resource.class)
public class Multifield {
 
 // Inject the products node under the current node
 @Deleted Account
 public Resource products;
 
 // No need of a post construct as we don't have anything to modify after the
 // model is constructed
}
 

and HTL code like

<div
    data-sly-use.multiItems="aem.community.mf.core.models.Multifield">
    <div data-sly-list.head="${multiItems.products.listChildren}">
 
 
  <div style="height:250px;"><img src=${head.pathbr} height=200 width=270 style="padding:4px"/><h2>${head.product}</h2>
                             <p>${head.desc}</p>
 
                             </div>
                             <hr>
 
   </div>
</div>

 

Hope this will help.

Umesh Thakur

View solution in original post

9 Replies

Avatar

Correct answer by
Community Advisor

First of all you should not make your sling model adaptables to SlingHttpServletRequest specially to get value from multifiled. then you made a mistake by trying to directly inject your resource for multifield. These are some mistake you have done prima-facie.

Please go thru the below article which fits 100% in your requirement.

https://helpx.adobe.com/experience-manager/using/aem64_htl_repeat_slingmodel.html

Just see the sling model 

 

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import javax.inject.Named;
 
import org.apache.sling.api.resource.Resource;
import org.apache.sling.models.annotations.Default;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.annotations.Optional;
import org.apache.sling.settings.SlingSettingsService;
 
@Model(adaptables = Resource.class)
public class Multifield {
 
 // Inject the products node under the current node
 @Deleted Account
 public Resource products;
 
 // No need of a post construct as we don't have anything to modify after the
 // model is constructed
}
 

and HTL code like

<div
    data-sly-use.multiItems="aem.community.mf.core.models.Multifield">
    <div data-sly-list.head="${multiItems.products.listChildren}">
 
 
  <div style="height:250px;"><img src=${head.pathbr} height=200 width=270 style="padding:4px"/><h2>${head.product}</h2>
                             <p>${head.desc}</p>
 
                             </div>
                             <hr>
 
   </div>
</div>

 

Hope this will help.

Umesh Thakur

Avatar

Level 3

Hello @Umesh_Thakur !

 

Thank you all for your responses. I have gone through all the responses and tested each one, however, I am stuck with an error now being output. As you can see, my code has been updated to Inject the cards as a Resource, I've removed the SlingHttpServletRequest, and I have tested by removing my getHeader function and even making a very simple model that only returns the cards, but this my error:

 

Any ideas??

Avatar

Community Advisor

@SocialTaylor Your code looks good to me now. If everything goes well, this has to execute. There can be few weird situations. Something like your jar bundles are not updated. Just for a cross verification, remove the bundle package completely from your system/console and reinstall and check if this resolves your issue. Adding some references below for this kind of issue. 

 

https://github.com/adobe/aem-component-generator/issues/19#issuecomment-559168608

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/no-use-provider-could-reso... 

https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/getting-error-msg-no-use-p...  ( this might not be valid in your case)

Avatar

Community Advisor

yes I can see issue in your code in the model annotation that is, you need to put adapters value in your case as you are inheriting one interface in your model.

You already had done in your existing code at line #21. so your final @Model will be like:

 

@Model(

adaptables = {Resource.class}, 

adapters = {HeroBannerComponent.class}, 

defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL)

public class HeroBannerComponentImpl implements HeroBannerComponent {

}

 

 

Hope this helps.

Umesh Thakur 

Avatar

Community Advisor

No need to have a different model for the same, same model will work here.

Only you need to get the Iterator object of the parent resource by calling the listChildren of it like:

Iterator iterator = parentResource.listChildren();

while(iterator.hasNext())

{

     Resource childResource = iterator.next();// here you have your child resources

// do what ever you want for child resources.

}

 

but will be better this if you create a list instead of passing the child resource to the sightly.

 

Hope this will help.

Umesh Thakur

Avatar

Community Advisor

Hi @SocialTaylor,

 

In the model, you are adapting it with SlingHttpRequest and trying to inject the multi field resource which will not work.

Try adding the Resource as one of the adatables (along with the request) or try this

@Inject @Via("resource")

Resource componentResource;

 

It should work.

Relevant URL's:

  1. https://sling.apache.org/documentation/bundles/models.html
  2. https://stackoverflow.com/questions/54454534/what-is-the-significance-of-declaring-a-sling-model-as-...

Hope this helps.

Thanks,

Kiran Vedantam.

Avatar

Community Advisor

@SocialTaylor There are few minor adjustments you have to do to your logic to get this work . Find below the sample model I did to just implement the very basic of your logic

Veena_Vikram_1-1629969200286.png

 

1. First point you have to understand is the naming conventions. Since your component's multifield has name cards , as you can see in your node structure , each items starting from item0 , item1,.... will get added to a node/ resource by name "cards" . So basically you have to inject the resource which has the name as "cards" .

Below image explains the nodes as per my component structure

Veena_Vikram_2-1629969742870.png

 

 In your code, at line 27,  you are trying to inject a resource componentResource . I am not sure from where you are referring that name. If we have to go by the names you have given and the nodes which are created , you should have been injecting the Resource as "cards"

2. Now as have I explained in another forum post https://experienceleaguecommunities.adobe.com/t5/adobe-experience-manager/usage-of-via-in-sling-mode... you have to use @Via("resource") to get any Resources in your model if you are adapting your model using SlingHttpServletRequest.class . 


But I think , since you don't need any request object in your model , you can better avoid using SlingHttpServletRequest.class and use only Resource.class ( Request is reccomended only when you need to use any object which Resource cannot provide) So may be you can rewrite your adaptable as something like below

Veena_Vikram_3-1629971725794.png

If you notice , in this case , you don't have to Inject it via resource , because your model is adapted via Resource.


Also , I think the logic you have written in the post construct is not needed. It can be simplified and done directly in the HTL as below 

@Inject
@Via("resource")

Resource cards;

public Resource getCards() {

return cards;
}


Return your cards resource via a getCards() method in the Model and do the below in the HTL

<div
data-sly-use.model="com.learn.practice.aem.core.models.MultifieldSampleModel">
<div data-sly-list.children="${model.cards.listChildren}">
${children.headerText}

${children.headerImage}
${children.content}
</div>
</div>

Depending on your requirement and FE rendering play around with this values in the HTL.

   Hope this helps. I tried to explain it the best I could, but still if you have any questions please let me know. Hope you get it resolved asap. Next time  don't wait for a week , but an extra eye might help to catch the issues Always feel free to come back to forum if you face any issues  

Veena ✌