Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

Server Side Handlebars Helper Disappears When Used in SCF Component

Avatar

Level 1

Hello, I have a server side handlebars helper that I'm trying to use inside of SCF components (Post, Topic, List-Item). It is working fine, but after the information shows up on the page, it disappears after a second.

Because our user profile nodes contain sensitive information in the properties, I cannot make them public as has been done for the geometrixx profiles. This is why I need to use a helper to get the username instead of using the oob {{author.name}}.

Here is the helper:

@Service @Component public class Username implements TemplateHelper<String>{ private final Logger LOGGER = LoggerFactory.getLogger(Username.class); @Reference private ResourceResolverFactory resourceResolverFactory; private static ResourceResolver resourceResolver; @Override public CharSequence apply(String context, Options options) throws IOException { try { if(resourceResolver == null) { resourceResolver = resourceResolverFactory.getAdministrativeResourceResolver(null); } Resource resource = resourceResolver.getResource(context); ValueMap vals = resource.getValueMap(); String userId = vals.get("userIdentifier").toString(); return userId; } catch (Exception e) { LOGGER.error("Error getting id from context - " + e); return "Default User"; } } @Override public String getHelperName() { return "username"; } @Override public Class<String> getContextType() { return String.class; } }

And then I use it like this in the components:

<p class="component-answerthread__profile-user">{{username this.id}}</p>

(This is done inside of the component's tag where data-component-id="{{id}}" is declared just to be clear.)

Like I said, this is working. It shows up for a second and then disappears. Oddly, it works flawlessly when the user is not logged in (it doesn't disappear).

1 Accepted Solution

Avatar

Correct answer by
Level 9

The documentation had the recommendation one-sided - if you create a client-side helper, you don't have to have a server-side helper.  Now it has a note that if you create a server-side helper you must have a client-side helper.

The client-side helper must have the same effect as the server-side, which would be difficult to accomplish for your task.

That is why you should really extend the AbstractUser class.  I was interacting with the team and they changed it from 'could' to 'should'. ;-)

The AbstractUser class essentially implements SocialComponent interface (Javadoc) :

"SocialComponents are POJOs that represent a resource for an AEM Communities feature.  Ideally, each SocialComponent represents a specific resourceType with exposed GETters that provide data to the client so the resource is accurately represented.  All business logic and view logic are encapsulated in the SocialComponent, including the site visitor's session information, if necessary.

The interface defines a basic set of GETters that are necessary to represent a resource. Importantly, the interface stipulates Map<String, Object> getAsMap() and String toJSONString() methods that are necessary in order to render Handlebars templates and expose GET JSON endpoints for resources."

Hope this helps.

- JK

View solution in original post

4 Replies

Avatar

Level 9

Hi,

The component's tag with attribute data-component-id (value is instance of component on page) also needs attribute data-scf-component (value is the resourceType).  All scf component templates must have all its markup inside the <div data-scf-component> tag.

Are you using either AEM 6.2 Communities FP1   or  AEM 6.1 Communities FP5 ?

Are you able to provide more context for the client side code?

Are there any errors reported?

- JK

Avatar

Level 9

Hi Dallas,

Two things :

1) a server side helper also has to be implemented on the client side (needs clarification in the documentation).

The component gets re-rendered on the clientside for logged in user, at this time, the client side helper is looked up, if not found, things disappear.

2) a better way is to subclass (extend) https://docs.adobe.com/docs/en/aem/6-2/develop/ref/javadoc/com/adobe/cq/social/scf/core/AbstractUser...

- JK

Avatar

Level 1

Hi JK, thanks for your time on this.

Yes, the documentation is a little misleading where it states it's not technically required (only recommended) to implement them both client and server side.

That being said, I did implement it on the client side the same way other server side helpers are defined such as 'includeClientLib' and 'if-wcm-mode' (otherwise it throws a js error 'Helper not found'). For testing purposes I just pasted my code into /etc/clientlibs/social/commons/scf/helpers.js to make sure it was being included correctly.

Here's how I implemented it client side: 

Handlebars.registerHelper("username", function(context, options) { // This helper only works on the server side. return ""; });

As for using the AbstractUser interface, wouldn't that still require making the profile node public? I think we'll just bite the bullet and move all the sensitive data out of the profile node and make the node public. 

 

Also sorry for deleting my other post. It was showing up twice so I hit delete on one of them and both were removed. Here's the code in case it is needed

<div class="component-answerthread__answer" class="scf scf-post {{#if _isNew}}scf-is-new{{/if}}" data-component-id="{{id}}" data-scf-component="social/qna/components/hbs/post"> <aside class=""> <a href="https://forums.adobe.com/content/sitename/profile.html/{{username this.id}}"> <img class="component-answerthread__profile-pic" src="{{author.largeAvatarURL}}"/> </a> <div class="component-answerthread__user-date-box"> <a href="https://forums.adobe.com/content/sitename/profile.html/{{username this.id}}"> <p class="component-answerthread__profile-user">{{username this.id}}</p> </a> <p class="component-answerthread__profile-time-stamp">{{pretty-time created}}</p> </div> </aside> <div class="component-answerthread__a-text"> {{{message}}} </div> <div class="{{#if topLevel}}withTopLevel{{/if}}"> {{#if configuration.isVotingAllowed}} {{include this.votes resourceType='social/tally/components/hbs/voting'}} {{/if}} {{include this template="toolbar"}} </div> </div>

Avatar

Correct answer by
Level 9

The documentation had the recommendation one-sided - if you create a client-side helper, you don't have to have a server-side helper.  Now it has a note that if you create a server-side helper you must have a client-side helper.

The client-side helper must have the same effect as the server-side, which would be difficult to accomplish for your task.

That is why you should really extend the AbstractUser class.  I was interacting with the team and they changed it from 'could' to 'should'. ;-)

The AbstractUser class essentially implements SocialComponent interface (Javadoc) :

"SocialComponents are POJOs that represent a resource for an AEM Communities feature.  Ideally, each SocialComponent represents a specific resourceType with exposed GETters that provide data to the client so the resource is accurately represented.  All business logic and view logic are encapsulated in the SocialComponent, including the site visitor's session information, if necessary.

The interface defines a basic set of GETters that are necessary to represent a resource. Importantly, the interface stipulates Map<String, Object> getAsMap() and String toJSONString() methods that are necessary in order to render Handlebars templates and expose GET JSON endpoints for resources."

Hope this helps.

- JK